Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execute different functions depending on template parameter disequation

This is definitely a trivial question, but I couldn't figure out how to do this.

I have a template function, say template <unsigned int N> void my_function(). Now, I have two different implementations for my_function, the first should be used if N is bigger than, say, 100, the other if N is smaller than that.

I tried to use SFINAE like this:

template <unsigned int N, typename = enable_if <N >= 100> :: type> my_function()
{
   // First implementation
}

template <unsigned int N, typename = enable_if <N < 100> :: type> my_function()
{
   // Second implementation
}

But that's declaring the same function two times. Then I tried doing something like

template <unsigned int N, bool = (N >= 100)> my_function();

And then implementing the two functions with the two different values of the boolean. No success, since it is a partial specialization.

Then I tried to wrap N as a struct parameter, and the bool in the function call, but it is specializing a member function before specializing the class, which cannot be done.

Is there a reasonable way to do this?

like image 905
Matteo Monti Avatar asked May 25 '15 14:05

Matteo Monti


2 Answers

Try this instead:

#include <type_traits>
#include <iostream>

template <unsigned int N, typename std::enable_if <N >= 100> :: type* = nullptr> 
void my_function()
{
    std::cout << "N >= 100" << std::endl;
}

template <unsigned int N, typename std::enable_if <N < 100> :: type* = nullptr> 
void my_function()
{
   std::cout << "N < 100" << std::endl;
}

int main()
{
    my_function<42>();
    my_function<100>();
}

Template default parameters do not participate in the overload (and hence SFINAE does not apply). On the other hand, in the snippet above, the dependent template non-type parameter is on the left hand side of the assignment, so SFINAE kicks in.

like image 93
vsoftco Avatar answered Oct 25 '22 22:10

vsoftco


If you don't like enable_if for some reason, you can always go for tag dispatch:

#include <type_traits>
class low {};
class high {};
template <int N, class T>
   void func(T, low)
   {
      // version for high N
   }
template <int N, class T>
   void func(T, high)
   {
      // version for low N
   }
template <int N, class T>
   void func(T val)
   {
      func<N>(val, std::conditional_t<(N>=100), high, low>{});
   }
int main()
{
   func<3>(3.14159); // low version
   func<256>("Yo"); // high version
}

In this case, we could restrict the tags to simple things like true_type and false_type, but in general this might be an alternative approach.

like image 26
Patrice Roy Avatar answered Oct 25 '22 21:10

Patrice Roy