Why is class A
compiling and class B
not compiling, where the compiler complains about having two declarations, are not both relying on SFINAE?
Both should actually use template type deduction when using foo
?
So the question really is, whats the subtle different in these two version
and why is class A
successfully using sfinae...?
- Class A uses a value-defaulted (zero) annonymous (not necessary) non-type template parameter
- Class B uses a type-defaulted (with enable_if) annonymous type template parameter
The code:
template<typename T>
struct A
{
template<typename U,
typename std::enable_if<!std::is_floating_point<U>::value>::type * = nullptr
>
void foo() {}
template<typename U,
typename std::enable_if<std::is_floating_point<U>::value>::type * = nullptr
>
void foo() {}
};
template<typename T>
struct B
{
template<typename U,
typename = typename std::enable_if<!std::is_floating_point<U>::value>::type
>
void foo() {}
template<typename U,
typename = typename std::enable_if<std::is_floating_point<U>::value>::type
>
void foo() {}
};
Live code at: http://coliru.stacked-crooked.com/a/40ec5efc7ba2a47c
§1.3.22 defines the signature of a function template:
The template parameter list does not include the default arguments given. For
A::foo
, the template parameters are not equivalent (a term precisely defined in §14.5.6.1). InB::foo
, they are. You're simply declaring the same function template with different default arguments - and thereby violate both §9.2/1 and §14.1/12.This is a common problem when overloading function templates solely by a condition for
enable_if
. In particular for constructors, where you can't place theenable_if
part in the return value.In
class B
, bothfoo
have same signature (even if they are different default value):So the error for class B.
In class A, the type are literally different (even if they both ends to
void
)