SFINAE method completely disables base class's template method in clang

梦想的初衷 提交于 2019-12-19 17:15:33

问题


#include <iostream>
#include <utility>

struct B {
    template<typename T, std::enable_if_t<std::is_same<T, int>::value>* = nullptr>
    void foo(T) {
        std::cout<<"B::foo"<<std::endl;
    }
};

struct D: B {        
    using B::foo;
    template<typename T, std::enable_if_t<std::is_same<T, std::string>::value>* = nullptr>
    void foo(T) {
        std::cout<<"D::foo"<<std::endl;
    }
};

int main() {
    D d;
    d.foo(2); // gcc: print "B::foo"; clang: compile error
    return 0;
}

Let's say we want to expose both foo() overloads in derived class D. gcc and Visual Studio compiles and print "B::foo" as I expected. But I get a compile error with clang:

prog.cc:22:7: error: no matching member function for call to 'foo'
    d.foo(2);
    ~~^~~
prog.cc:14:10: note: candidate template ignored: requirement 'std::is_same<int, std::string>::value' was not satisfied [with T = int]
    void foo(T) {

Is this a clang bug? Thanks!


回答1:


I actually think this is a gcc bug (84832 is closely related, though as Wakely notes it's possible that this should be a core language issue).

From [namespace.udecl]/15:

When a using-declarator brings declarations from a base class into a derived class, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list, cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting). Such hidden or overridden declarations are excluded from the set of declarations introduced by the using-declarator.

Where a parameter-type-list is defined in [dcl/fct]/5:

The type of a function is determined using the following rules. The type of each parameter (including function parameter packs) is determined from its own decl-specifier-seq and declarator. After determining the type of each parameter, any parameter of type “array of T” or of function type T is adjusted to be “pointer to T”. After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type. The resulting list of transformed parameter types and the presence or absence of the ellipsis or a function parameter pack is the function's parameter-type-list.

B::foo and D::foo have the same name ("foo"), parameter-type-list ([T]), cv-qualification (none), and ref-qualifier (none). Hence, the derived one hides the base one.



来源:https://stackoverflow.com/questions/51933397/sfinae-method-completely-disables-base-classs-template-method-in-clang

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!