2

After reading questions such as sfinae on member function defined outside of class body (which isn't the same question), and other, I still don't get the good way to define the body of a member function outside the class declaration when using a SFINAE approach to enable the class only with arithmetic types.

#include <type_traits>

template <typename T,typename = typename std::enable_if<std::is_arithmetic<T>::value,T>::type>
class foo
{
public:
    void bar();
};

template <typename T>
void foo<T>::bar ()
{
}

In this example, I get the error :

error: invalid use of incomplete type 'class foo<T>'
void foo<T>::bar ()
^
error: declaration of 'class foo<T>'
class foo
^

Whereas if I declare it like so :

#include <type_traits>

template <typename T,typename = typename std::enable_if<std::is_arithmetic<T>::value,T>::type>
class foo
{
public:
    void bar()
    {
    }
};

It functions without any trouble whatsoever.

I am using mingw-w64 (w64 3.3) to compile this code.

Community
  • 1
  • 1
Pierre-Antoine Guillaume
  • 1,047
  • 1
  • 12
  • 28

1 Answers1

5

foo has two template parameters, even if one of them is unnamed, defaulted and used for SFINAE. Hence:

template <typename T, typename U>
void foo<T, U>::bar ()
{
}
Quentin
  • 62,093
  • 7
  • 131
  • 191
  • in this case, how come if you declare a function taking two foo as const ref parameters, you don't need to specify the second typename ? – Pierre-Antoine Guillaume Jan 17 '17 at 23:45
  • @PierreAntoineGuillaume Such as `void baz(foo const &)` ? That's because it is simply using (instantiating) `foo`. Defining `foo`, on the other hand, requires you to be explicit about what part of which `foo`s you're on about. Your syntax *could* have meant "use the default parameter", but in your case you'd be defining a single member function of a partial specialization (`foo`), [which is not permitted](http://stackoverflow.com/questions/12335762/partial-specialization-of-member-function). – Quentin Jan 18 '17 at 09:07