Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clang fails to find const template member function from base class

The following C++ file:

struct Base {
    template <typename T, int = 42>
    void f(T &&) const {}
};

struct Derived: Base {
    template <typename T, typename X = typename T::asdf>
    void f(T &&) const {}

    using Base::f;
};

int main() {
    Derived const cd;
    cd.f('x');
}

compiles well with GCC but not with Clang:

$ g++-7.3.0 -std=c++11 test.cpp -o test -Wall -Wextra
$ g++-7.2.0 -std=c++11 test.cpp -o test -Wall -Wextra
$ g++-6.4.0 -std=c++11 test.cpp -o test -Wall -Wextra
$ g++-5.4.0 -std=c++11 test.cpp -o test -Wall -Wextra
$ g++-4.9.4 -std=c++11 test.cpp -o test -Wall -Wextra
$ clang++-4.0 -std=c++11 test.cpp -o test -Wall -Wextra
test.cpp:15:12: error: no matching member function for call to 'f'
        cd.f('x');
        ~~~^
test.cpp:8:14: note: candidate template ignored: substitution failure [with T = char]: type 'char' cannot be used prior to '::' because it has no members
        void f(T &&) const {}
            ^
1 error generated.
$ clang++-5.0 -std=c++11 test.cpp -o test -Wall -Wextra
test.cpp:15:12: error: no matching member function for call to 'f'
        cd.f('x');
        ~~~^
test.cpp:8:14: note: candidate template ignored: substitution failure [with T = char]: type 'char' cannot be used prior to '::' because it has no members
        void f(T &&) const {}
            ^
1 error generated.
$ clang++-6.0 -std=c++11 test.cpp -o test -Wall -Wextra
test.cpp:15:12: error: no matching member function for call to 'f'
        cd.f('x');
        ~~~^
test.cpp:8:14: note: candidate template ignored: substitution failure [with T = char]: type 'char' cannot be used prior to '::' because it has no members
        void f(T &&) const {}
            ^
1 error generated.

Why doesn't it compile with Clang? Is my code correct? Is this a compiler bug? A bug in the C++ standard?

like image 984
jotik Avatar asked Mar 12 '18 12:03

jotik


1 Answers

I think this is a gcc bug.

According to the using-declarator (emphasis mine):

[namespace.udecl]

The set of declarations introduced by the using-declarator is found by performing qualified name lookup ([basic.lookup.qual], [class.member.lookup]) for the name in the using-declarator, excluding functions that are hidden as described below.

...

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.

In your case, the base class f() should be hidden, and invisible to the derived class.

Another important point is, the effect of using is at name-lookup stage, before SFINAE. Thus whether there is a SFINAE has no impact.

like image 57
llllllllll Avatar answered Nov 14 '22 04:11

llllllllll