Martin Perry
Martin Perry

Reputation: 9527

C++11 Template conditional

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

Answers (3)

Piotr Skotnicki
Piotr Skotnicki

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 :

template <typename T>
    requires std::is_arithmetic_v<T>
class Foo
{
    // ...
};

Upvotes: 3

Marco A.
Marco A.

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
}

Live Example

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() {
}

Live Example

Upvotes: 1

Andrey Nasonov
Andrey Nasonov

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

Related Questions