SFINAE for class member function (one compiles the

2019-06-02 08:40发布

问题:

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:

§1.3.22 defines the signature of a function template:

signature
<class member function template> name, parameter type list (8.3.5), class of which the function is a member, cv-qualifiers (if any), ref-qualifier (if any), return type, and template parameter list

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). In B::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 the enable_if part in the return value.



回答2:

In class B, both foo have same signature (even if they are different default value):

template <typename U, typename Dummy>
void foo();

So the error for class B.

In class A, the type are literally different (even if they both ends to void)