Search code examples
c++templatesdependent-name

Why `this` is a type-dependent expression even if the template class has no base class?


The following code can be compiled without error:

template <typename T> struct A {
    void f() { this->whatever; } // whatever is not declared before
};
int main() {
    A<int> a;
}

And I know it's because this is a type-dependent expression, which makes name lookup for whatever is postponed until the actual template argument is known. Since member function f() is never used in this case, so that no instantiation of A<T>::f exists, and name lookup for whatever is never performed.

I can understand that this is type-dependent if the class template has a type-dependent base like:

template <typename T> struct B { T whatever; };
template <typename T> struct A : B<T> {
    void f() { this->whatever; }
};
int main() {
    A<int> a;
}

When parsing the definition of template class A, it's impossible to know what's type of its base, which makes this->whatever potentially legal (B<T> could has a member named whatever). On the contrary, I haven't see any potential that this->whatever would be legal in the first example as soon as member function f is used somewhere.

So, could this->whatever be legal at some points in the first example? If not, is there any other reason that this should be treated as type-dependent expression in that case?


Solution

  • Your code is "ill-formed, no diagnostic required", because there is never a valid specialization for A::f. In fact, the spec says that this->whatever is neither a member of an unknown specialization (because there is no dependent base class), nor a member of the current instantiation (because it's not declared in a non-dependent base class, nor in the class template itself). This in addition renders your code invalid, and again no diagnostic is required (but allowed). This is explained in more details at https://stackoverflow.com/a/17579889/34509

    this is type-dependent because you don't know the template parameter values yet in the definition. So for instance SomeOtherTemplate<decltype(*this)> cannot be resolved immediately, but needs to wait till the class template of this is instantiated (so you need a typename before SomeOtherTemplate<decltype(*this)>::type).

    However, just because this is type dependent, doesn't mean that this->whatever is aswell. As described above, the spec has tools to correctly categorize this as invalid, and in fact also does not make this->whatever type dependent. It says

    A class member access expression ([expr.ref]) is type-dependent if the expression refers to a member of the current instantiation and the type of the referenced member is dependent, or the class member access expression refers to a member of an unknown specialization.