How to seperate declaration and implementation of a templated class with a default template parameter?

Viewed 755

I like to separate the declaration and implementation of my classes. I know that the implementation of class templates and function also has to go into the header file, that's not the problem.

I'm having trouble implementing this class:

template <size_t S, std::enable_if_t<(S > 0), int> = 0>
class Foo {
public:
    Foo();
}

So far I have tried:

template<size_t S>
Foo<S>::Foo() {}

which failed with

error C3860: template argument list following class template name must list parameters in the order used in template parameter list

error C2976: 'Foo<S,<__formal>>' : too few template arguments

and

template<size_t S, int i>
Foo<S, i>::Foo() {}

which failed with

error C3860: template argument list following class template name must list parameters in the order used in template parameter list

error C3855: 'Foo<S,<unnamed-symbol>>' : template parameter '__formal' is incompatible with the declaration

I have also tried changing the template declaration to

template <size_t S, typename = std::enable_if_t<(S > 0)>>

which also failed with the first error message.

What is the correct way of doing this?

3 Answers

You cannot partially specialize template functions (that's what you're doing in the first snippet). If you're asking about how to define it outside the class, try this:

template <size_t S, std::enable_if_t<(S > 0), int> j>
Foo<S, j>::Foo(){}

You cannot just replace std::enable_if_t<(S > 0), int> by int, as the definitions are not equivalent (the enable_if one SFINAEs out the S == 0 case).

Live snippet

Keep it simple:

template <size_t S>
class Foo {
public:
    Foo();
};

template <size_t S>
Foo<S>::Foo() { }

template <>
class Foo<0>;

In this particular case, I'm not sure adding SFINAE gives you any extra benefits. It's possible that even the explicit specialization is unnecessary, and just a simple static_assert(S > 0, "!") would suffice.

What is the correct way of doing this?

I suppose the second one you've tried, with the typename.

Given

template <size_t S, typename = std::enable_if_t<(S > 0)>>
class Foo {
public:
    Foo();
};

the constructor can be defined as

template <std::size_t S, typename T>
Foo<S, T>::Foo() {}

A full compiling example

#include <iostream>
#include <type_traits>

template <size_t S, typename = std::enable_if_t<(S > 0)>>
class Foo {
public:
    Foo();
};

template <std::size_t S, typename T>
Foo<S, T>::Foo() {}

int main ()
 {
   Foo<12U>  f12;   // compile
   // Foo<0U>   f0; // compilation error
 }
Related