Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to disable a class member function for certain template types

It seems to be simple, but I have some difficulties with the syntax of std::enable_if

The situation is actually quite simple.

a template class with template parameter T

2 functions which shall not be implemented for one specific type of T.

Both functions have no parameters or return values of T

One function accepts an int and the other function returns an int.

Any simple example ?

Or is there another option (C++11) which does not use std::enable_if ?

like image 282
Waldorf Avatar asked Mar 27 '17 16:03

Waldorf


1 Answers

It's really simple. Just remember to use another template parameter that is defaulted to the class/struct template parameter.

Suppose you want a class foo<T> with two members, void foo<T>::bar1 (int) and int foo<T>::bar2 () and suppose that you want that bar1() and bar2() are implemented only if T is different from long.

You can do as follows

#include <type_traits>

template <typename T>
struct foo
 {
   template <typename U = T>
   typename std::enable_if<false == std::is_same<U, long>::value>::type
      bar1 (int)
       { }

   template <typename U = T>
   typename std::enable_if<false == std::is_same<U, long>::value, int>::type
      bar2 ()
       { return 0; }
 };

int main()
 {
   foo<int>  fi;
   foo<long> fl;

   fi.bar1(0); // compile
   fi.bar2();  // compile

   // fl.bar1(0); // compilation error
   // fl.bar2();  // compilation error
 }

There is a danger: someone can bypass your control and explicit the U type as follows

foo<long> fl;

fl.bar1<long long>(0);

To avoid this problem, you can improve your std::enable_if test as follows

   template <typename U = T>
   typename std::enable_if
         <sizeof(U) && (false == std::is_same<T, long>::value)>::type
      bar1 (int)
       { }

   template <typename U = T>
   typename std::enable_if
         <sizeof(U) && (false == std::is_same<T, long>::value), int>::type
      bar2 ()
       { return 0; }

If you can use a C++14 compiler, using std::enable_if_t you can avoid a couple of typename and a couple if ::type and semplify the code as follows

   template <typename U = T>
   std::enable_if_t<sizeof(U) && (false == std::is_same<T, long>::value)>
      bar1 (int)
       { }

   template <typename U = T>
   std::enable_if_t<sizeof(U) && (false == std::is_same<T, long>::value), int>
      bar2 ()
       { return 0; }
like image 179
max66 Avatar answered Oct 21 '22 15:10

max66