Qualified dependent name lookup with injected-class-name of base class

Viewed 80

The most recent versions of clang, gcc and msvc (/permissive-) all reject the following code:

struct B {
    void func() {}
};

template<typename T>
struct Base : B {
    void func() {}
};

template<typename T>
struct Derived : Base<T> {
    void func() {
        this->Base::func(); // (*) fails here, even though this->B::func(); works
    }
};

// for msvc, use /permissive- and the following instantiation for the error to trigger:
int main() {
    Derived<void> d;
    d.func();
}

My understanding of the current standard is that (*) is considered a member of an unknown specialization, according to https://eel.is/c++draft/temp#dep.type-6.3 , and therefore, name resolution would be delayed to template instantiation, but given that (*) is also a qualified function call, the lookup should also be performed in the base class even though it's dependent, and it should then find the injected-class-name: Base.

Is this code really invalid or is it a compiler bug? What am I missing?

1 Answers

In the class member access expression this->Base::func, the id-expression is Base::func. Inside this expression, Base is not a member of an unknown specialization.

If you want this to be a member of an unknown specialization you must qualify it with the injected class name:

template<typename T>
struct Derived : Base<T> {
    void func() {
        this->Derived::Base::func(); // compiles: Base is now a member of an unknown specialization
    }
};
Related