Reputation: 9527
I want to write template with conditional for only numbers.
//in header file
template <typename T,
typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type
>
class Foo
{
public:
Foo();
};
#include "Foo.inline"
And
//In inline file
template <
typename T
>
Foo<T>::Foo()
{
};
However, this does not compile. How should be the syntax to have template implementation in separate file?
Upvotes: 1
Views: 150
Reputation: 48527
std::enable_if
is useful for triggering a substitution failure, so that the compiler can fallback to another overload/specialization.
If you want to verify a template argument, put an appropriate condition in a static_assert
:
template <typename T>
class Foo
{
static_assert(std::is_arithmetic<T>::value,
"T must be an arithmetic type");
public:
Foo();
};
template <typename T>
Foo<T>::Foo()
{
}
Or a constraint c++20:
template <typename T>
requires std::is_arithmetic_v<T>
class Foo
{
// ...
};
Upvotes: 3
Reputation: 43662
The problem with your code is that you're defaulting the second template argument to T
if the first one satisfies is_arithmetic
. This will work for case 1 but not for case 2
template <typename T,
typename U = typename std::enable_if<std::is_arithmetic<T>::value, T>::type>
class Foo {
public:
Foo();
};
template <typename T, typename U>
Foo<T, U>::Foo() {
}
struct Obj {};
int main() {
Foo<int> obj; // Fine
// Foo<Obj> obj2 // 1) Error - as it should be
Foo<std::string, Obj> obj3; // 2) Works fine - bad
}
in order to avoid instantiation if the first type isn't valid for is_arithmetic
you should use a static_assert
template <typename T>
class Foo {
static_assert(std::is_arithmetic<T>::value, "T is not an arithmetic type");
public:
Foo();
};
template <typename T>
Foo<T>::Foo() {
}
Upvotes: 1
Reputation: 2629
The second template parameter should be used in the definition.
//in header file
template <typename T,
typename Enable = typename std::enable_if<std::is_arithmetic<T>::value, T>::type
>
class Foo
{
public:
Foo();
};
//In inline file
template <typename T, typename Enable>
Foo<T, Enable>::Foo()
{
};
Upvotes: 1