c++ enable_if for non-type template parameters
You can totally do what you want with enable_if
, just remember, the substitution has to fail when the condition is false, so you must call type
to ensure the substitution fails when specializing for various conditions.
#include <stdio.h>
#include <iostream>
#include <type_traits>
template <typename T, int DIM>
class foo
{
public:
template <int D = DIM>
typename std::enable_if<D == 1, T>::type
function()
{
// do something
return 1.0;
}
template <int D = DIM>
typename std::enable_if<D == 2, T>::type
function()
{
// do something else
return 2342.0;
}
};
int main(){
foo<int, 1> object;
int ak = object.function();
std::cout << ak << "\n";
return 0;
}
For simple scenarios, like the one above (where you check a specific value, rather than a range of values), you can also use partial specialization. But if you would like to specialize, say, for all values from 1-50
, another for 51-200
, and then a generic fallthrough, enable_if
works great.
You can also use enable_if
in the template signature. Just a quick example.
#include <stdio.h>
#include <iostream>
#include <type_traits>
template <typename T, int DIM>
class foo
{
public:
template <int D = DIM, typename std::enable_if<D == 1, void>::type* = nullptr>
T function()
{
// do something
return 1.0;
}
template <int D = DIM, typename std::enable_if<D == 2, void>::type* = nullptr>
T function()
{
// do something else
return 2342.0;
}
};
int main(){
foo<int, 1> object;
int ak = object.function();
std::cout << ak << "\n";
return 0;
}
You can partial specialize the whole class:
template <typename T, int DIM>
class foo;
template <typename T>
class foo<T, 1>
{
public:
T function() {
// do something
return 1.0;
}
};
template <typename T>
class foo<T, 2>
{
public:
T function() {
// do something
return 2342.0;
}
};
If you have lot of common code between both specialization, you may still use inheritance (inherit from common part or just the specialized part).
An easy alternative way is to use Tag dispatching:
template <typename T, int dim>
class foo
{
public:
T function();
};
template <typename T>
T function_helper(foo<T, 1>&) {
// do something
return 1.0;
}
template <typename T>
T function_helper(foo<T, 2>&) {
// do something
return 2342.0;
}
template <typename T, int dim>
T foo::function() {
return function_helper(*this);
}
But in C++17, if constexpr
allows simpler syntax:
template <typename T, int DIM>
class foo
{
public:
T function() {
if constexpr (DIM == 1) {
// do something
return 1.0;
} else if constexpr (DIM == 2) {
// do something
return 2342.0;
}
}
};