Reputation: 8940
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?
Upvotes: 15
Views: 6487
Reputation: 101
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.
Upvotes: 5
Reputation: 56547
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.
Upvotes: 12
Reputation: 217235
You may use SFINAE on return type:
template <unsigned int N>
enable_if_t<(N >= 100)> my_function()
{
// First implementation
}
template <unsigned int N>
enable_if_t<(N < 100)> my_function()
{
// Second implementation
}
currently, you have only template <unsigned int N, typename T>
with different default type for T
.
For the partial specialization, you may forward to structure:
template <unsigned int N, bool = (N >= 100)>
struct my_function_impl;
template <unsigned int N>
struct my_function_impl<N, true>
{
void operator () const { /* First implementation */}
};
template <unsigned int N>
struct my_function_impl<N, false>
{
void operator () const { /* Second implementation */}
};
template <unsigned int N>
void my_function() { my_function_impl<N>{}(); }
Upvotes: 2