1

I have a template class for which certain member functions only make sense if the template parameters satisfy certain conditions. Using, for instance, std::enable_if<> I can define them only for these cases, but how can I call them conditionally? Here is a brief example

template<class T> class A
{
   typename std::enable_if<std::is_floating_point<T>::value>::type a_member();
   void another_member()
   {
     a_member(); // how to restrict this to allowed cases only?
   }
};
Walter
  • 44,150
  • 20
  • 113
  • 196

2 Answers2

9

Firstly, you can't use SFINAE like that - the template type parameter needs to be on the function, not the class.

A full solution looks like this:

template<class T> class A
{
private:
   template <class S>
   typename std::enable_if<std::is_floating_point<S>::value>::type a_member() {
       std::cout << "Doing something";
   }

   template <class S>
   typename std::enable_if<!std::is_floating_point<S>::value>::type a_member() {
       //doing nothing
   }

public:
   void another_member()
   {
     a_member<T>();
   }
};


int main() {
    A<int> AInt;
    AInt.another_member();//doesn't print anything

    A<float> AFloat;
    AFloat.another_member();//prints "Doing something"
}
JoeG
  • 12,994
  • 1
  • 38
  • 63
  • +1 great! I tried that, but without the additional template over S, which is critical to avoid function overload. – Walter Jul 06 '12 at 14:30
  • 1
    The extra template parameter isn't to avoid ambiguous overloads. SFINAE works only on function templates, not class templates so you need to make those functions templates. – JoeG Jul 06 '12 at 14:41
  • this is semantics. In order to use SFINAE, one needs different function signatures and an ambiguous overload cannot give that (my compiler (gcc/4.7.0) complains about overload). – Walter Jul 06 '12 at 16:34
  • @Walter: It's not semantics - SFINAE only works on template functions. If you resolve the overload ambiguity by giving two non-template functions different argument lists, it still won't work. – JoeG Jul 06 '12 at 18:36
  • It would be nice to complete this answer with the fact that there is a proposition to the next C++ standard (from D language designers) that add the famous static if that would be far far more elegant than enable if. – Klaim Jul 07 '12 at 02:53
1

WARNING: This is a complete, terrible hack that I have not tried that may never work.

Try adding this to the class declaration:

typename std::enable_if<std::is_floating_point<T>, int*>::type a_enabled_p() { return 0;};
void another()
{
  if((a_enabled_p()+1)==1)
  {
    //Not enabled
  }
  else if((a_enabled_p()+1)==sizeof(int))
  {
    //Is enabled
  }
}

Here's why this horror might work. If they are floating point, the return value of the predicate is an int*. If they are, there is no typedef, and it defaults to int (I hope). When you add 1 to an int*, you are really adding sizeof(int). Adding 1 to an int increments by one. That means that by checking the value of adding one, we know.

Note: Don't use this. It was fun to come up with, but the above answer is MUCH, MUCH

MUCH

Better. Don't use this. Please.

Linuxios
  • 34,849
  • 13
  • 91
  • 116
  • this is a run-time version and will not compile (your "not enabled" code is only not called, but still enabled). – Walter Jul 06 '12 at 14:27
  • @Walter: I never said it would work, but why? How? This is the first time I've even seen `std::enable_if`, so please enlighten me. – Linuxios Jul 06 '12 at 14:30