Why is template function of data member a dependent name only when qualifying with "this"?

c++, c++11, dependent-name, templates

Solution

this->bar.baz<int>(); // error

The statement above, within the definition of `template<typename T> Foo<T>::Foo()`, is well-formed, and should be accepted if C++11 mode or C++1y mode is enabled. But it was technically ill-formed according to C++03.

Both standards agree that `this` is a type-dependent expression:

C++03 14.6.2.1/1; N3690 14.6.2.1/8:

A type is dependent if it is

a template parameter,

...

a [simple-]template-id in which either the template name is a template parameter or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent,

[`T` is a dependent type, and so is `Foo<T>`.]

C++03/N3690 14.6.2.2/2:

`this` is type-dependent if the class type of the enclosing member function is dependent.

[Since `Foo<T>` is a dependent type, the expression `this` in its member definition is type-dependent.]

Both standards begin 14.6.2.2 with:

Except as described below, an expression is type-dependent if any subexpression is type-dependent.

C++03 has only three simple categories of expressions with more exact descriptions:

Primary expressions (`this` and looked-up names)

Expressions that specify their own type (like casts and new-expressions)

Expressions with constant type (like literals and `sizeof`).

The first category is defined in C++03 14.6.2.2/3:

An id-expression is type-dependent if it contains:

an identifier that was declared with a dependent type,

a template-id that is dependent,

a conversion-function-id that specifies a dependent type,

a nested-name-specifier that contains a class-name that names a dependent type.

So the lone expression `bar` is not dependent: it is an identifier and an id-expression, but none of the above apply.

But `this->bar` is not an id-expression, or in any of the other C++03 exceptions, so we have to follow the subexpression rule. Since subexpression `this` is type-dependent, the containing expression `this->bar` is also type-dependent.

But in fact, as you noticed, the type of `this->bar` can be known while parsing the template definition, without instantiating any template arguments. It is declared as a member of the primary template, so the name must bind to that member declaration. A template specialization might make `Foo<T>::bar` undeclared or declared in a different way, but in that case the primary template won't be used at all and the current definition of `Foo()` is ignored for that specialization. Which is why C++11 defined the concept of "the current instantiation" and used it for a further exception to the contagiousness of type-dependent expressions.

N3690 14.6.2.1/1:

A name refers to the current instantiation if it is

in the definition of a class template, a nested class of a class template, a member of a class template, or a member of a nested class of a class template, the injected-class-name of the class template or nested class

in the definition of a primary class template or a member of a primary class template, the name of the class template followed by the template argument list of the primary template (as described below) enclosed in `<>` (or an equivalent template alias specialization),

...

[The first bullet says `Foo` is the current instantiation. The second says `Foo<T>` is the current instantiation. In this example, both name the same type.]

14.6.2.1/4:

A name is a member of the current instantiation if it is

An unqualified name that, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof.

A qualified-id in which ...

An id-expression denoting the member in a class member access expression for which the type of the object expression is the current instantiation, and the id-expression, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof.

[The first bullet says `bar` alone is a member of the current instantiation. The third bullet says `this->bar` is a member of the current instantiation.]

Finally, C++11 adds a fourth category of rules for type-dependent expressions, for member access. 14.6.2.2/5:

A class member access expression 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.

`this->bar` does refer to a member of the current instantiation, but the type `Bar` of the referenced member is not dependent. So now `this->bar` is not type-dependent, and the name `baz` in `this->bar.baz` is looked up during the template definition as a non-dependent name. The `template` keyword is not needed before `baz`.

Problem

``` struct Bar { template<typename> void baz() { } }; template<typename> struct Foo { Bar bar; Foo() { bar.baz<int>(); } }; int main() { return 0; } ``` This code compiles fine (in GCC 4.7), but if I prefix the call to `bar.baz<int>()` with `this->`, `baz` becomes a dependent name that needs disambiguating with `template`. ``` bar.baz<int>(); // OK this->bar.baz<int>(); // error this->bar.template baz<int>(); // OK ``` Surely `this->bar` can only refer to `Bar bar`, whose member `baz` is clearly a template? Why does the addition of `this->` make this code ambiguous to the compiler? p.s. Originally, `bar` was a data member of a base class template which needed disambiguating with `this->`, but I have simplified the example for the purpose of this question.

Original source

Related problems