14
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.

Joseph Thomson
  • 9,888
  • 1
  • 34
  • 38

3 Answers3

4
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.

Community
  • 1
  • 1
aschepler
  • 70,891
  • 9
  • 107
  • 161
  • `this->bar.baz` is another class member access where `this->bar` does not refer to the current instantiation, and a subexpression (`this`) is dependent. I do agree that the intent in [CWG DR 224](http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#224) seems to have been that `this->bar.baz` should not be dependent, since it can be looked up at the point of definition; but I think the rules do not cover this case. – dyp Jul 06 '14 at 10:59
  • @dyp 14.6.2.2/5 covers all class member access expressions. Since `this->bar.baz` is neither a member of the current instantiation nor a member of an unknown specialization, it is not type-dependent. Also, if "subexpression" in 14.6.2.2 means any recursive subexpression, not just direct operands, wouldn't that imply `(sizeof(this)+0)` is type-dependent? – aschepler Jul 06 '14 at 12:59
  • `sizeof(this)` must certainly be dependent if there are dependent base classes, whose size is not known until the point of instantiation. But it is not type-dependent but value-dependent; my interpretation of [temp.dep.expr]/4 is that the *type* of `sizeof(...)` cannot be dependent. `this->bar` is a dependent expression but refers to a member of the current instantiation. Hence, [temp.dep.type]/5 applies to `this->bar.baz` which says that an *id-expression* in a class-member-access-expression is dependent if the type of the object expression is dependent and not **the** current instantiation. – dyp Jul 06 '14 at 13:36
  • Why do you say `this->bar` is dependent, and what exactly do you mean? – aschepler Jul 06 '14 at 15:30
  • Hm. I think I understand your argument now: If we take [temp.dep.expr]/5 as the *sole* definition of dependency in class-member-access-expressions (replacing "if the expression" with "iff the expression"), then `this->bar` is not dependent. +1 – dyp Jul 06 '14 at 16:25
  • If I understand correctly, you are saying that the sub-expression `this->bar` *is* a class-member-access-expression, so `this->bar` is *not* dependent and therefore neither is `this->bar.baz`. So the addition of *"the expression refers to a member of the current instantiation and the"* to the specification seems to be what makes all the difference... Would you say, therefore, that it seems that the compilers are incorrectly determining that `baz` in `this->bar.baz` is not a member of the current-instantiation, without first checking the membership of `bar`? – Joseph Thomson Jul 06 '14 at 19:31
  • I'm not sure exactly what the compiler is doing, but: `this->bar` is not dependent because it's a member of the current instantiation *and* the type of that member is not a dependent type. (If you had `std::vector bar;` instead, `this->bar` would be dependent again.) `this->bar.baz` is *not* a member of the current instantiation. But since `this->bar` is not dependent, `this->bar.baz` is not a dependent name. – aschepler Jul 06 '14 at 19:58
  • While the various answers here are not in agreement, I will accept this one because a) you seem to have convinced dyp, b) because you provided a comprehensive and focused answer to my question, and c) because I find your explanation convincing. Of course, if someone else shows otherwise, I may change my mind ;) – Joseph Thomson Jul 07 '14 at 15:47
3

Short summary

This is just the way the current C++11 rules are: this->bar.baz<int>() introduces a dependent name not in the current instantiation context that requires disambiguation with the template keyword, even though it is very hard to come up with an actual example of a competing parse that change the semantics of the expression this->bar.baz<int>().

Parsing ambiguity from angle brackets

First: why in general is there a need for template?

When a C++ compiler encounters an expression f<g>(0), it can interpret this either as "call the function template f for template argument g and function argument 0 and evaluate the result" or it can mean "make the comparison (f<g)>(0) for names f and g and constant 0." Without further information it cannot make this decision. This is an unfortunate consequence of the choice of angle brackets for template arguments.

In many (most) cases, the compiler does have enough context to decide whether a template expression or a comparison is being parsed. However, when a so-called dependent name (essentially a name that is explicitly or implicitly dependent on a template parameter of the current scope) is encountered, another language subtlety comes into play.

Two-phase name lookup

Because a name dependent on a template could change its meaning (e.g. through specializations) when a template is being instantiated for a concrete type, name lookup of dependent names is done in two phases (quote from C++ Templates the Complete Guide):

During the first phase, nondependent names are looked up while the template is being parsed using both the ordinary lookup rules and, if applicable, the rules for argument-dependent lookup (ADL). Unqualified dependent names (which are dependent because they look like the name of a function in a function call with dependent arguments) are also looked up that way, but the result of the lookup is not considered complete until an additional lookup is performed when the template is instantiated.

During the second phase, which occurs when templates are instantiated at a point called the point of instantiation (POI), dependent qualified names are looked up (with the template parameters replaced with the template arguments for that specific instantiation), and an additional ADL is performed for the unqualified dependent names.

Why this-> makes your code different

Using this-> inside a class template introduces a dependent name and triggers two-phase name lookup. In that case, the rule cited by @40two comes into play. The point is that the ADL at the 2nd phase can bring in new names from explicit specializations that redefine the meaning of your bar and baz and it could conceivably change the meaning of this->bar.baz<int>(0) to a comparison rather than a function template call.

Granted, for non-type template arguments such as this->bar.another_baz<0>() this would be more likely than for a type template parameter. In this related Q&A a similar discussion arose whether one could find a syntactic valid form that changes the meaning of this->f<int>() vs this->template f<int>(0), without a clear conclusion.

Note that C++11 already relaxes the rule for template disambiguation compared to C++98. Under the current rules this->f<int>() for a template<class> f() inside Foo would not require template because it is in the so-called current instantiation. See this answer from the canonical Q&A for this topic for more details

Community
  • 1
  • 1
TemplateRex
  • 69,038
  • 19
  • 164
  • 304
  • Thanks for the answer. Why does using `this->` introduce a dependent name? I think this is the key point that I am not getting. – Joseph Thomson Jul 05 '14 at 19:21
  • @JosephThomson because `this` is of type `Foo*` which depends on `T`? – TemplateRex Jul 05 '14 at 19:24
  • Hmmm. Are you saying that `Foo` is a dependent type even within member functions of `Foo` where the members of `Foo` are unambiguous? I just can't think of an instance where the compiler would not know that `Foo::bar` is of type `Bar`. If `Foo` is specialized, `Foo<>::Foo()` will need to be redefined anyway. Are you saying that this is a result of C++ being conservative about what is a dependent type? – Joseph Thomson Jul 05 '14 at 19:32
  • 1
    As Schaub-litb mentions in the answer I linked: "While the rules in C++03 about when you need typename and template are largely reasonable, there is one annoying disadvantage of its formulation", being the example that you posted. In C++11 the `template` requirements got relaxed, perhaps it can be done even further. At least the current rule is not hard to apply (even though it adds a little clutter in rare cases where it might not be needed) – TemplateRex Jul 05 '14 at 19:36
  • I'm not particularly annoyed by the need to write an unnecessary `template`; I'm just trying to find out why! If `this->baz()` is of the current instantiation, shouldn't `this->bar.baz()` also be of the current instantiation? Or is it not, because according to 14.6.2.1 [temp.dep.type], the object expression `this->bar` is not the current instantiation? It's of type `Bar`, which despite being non-dependent, does not fall under this exception. – Joseph Thomson Jul 05 '14 at 20:06
  • @JosephThomson indeed, the rule could be taken further. In any case, this is a difficult area for compiler implementers, e.g. vc++ doesn't implement 2 phase lookup at all. Btw, the dependent bame rules are uniform, it's the template disambiguation rule which is irregular. – TemplateRex Jul 05 '14 at 20:13
  • *"even though it is very hard to come up with an actual example of a competing parse that change the semantics of the expression `this->bar.baz()`"* Simply change it to `this->bar.baz(0);` and you have an ambiguity. – dyp Jul 05 '14 at 20:31
  • @dyp yes but without the ()? – TemplateRex Jul 05 '14 at 20:32
  • Without the `()` it might be a typo. Whether or not `this->bar.baz()` is an error should not depend whether or not it can be looked up for the given types at the point of definition, otherwise you get order dependency. So you have to delay checking if `this->bar` is dependent, and requiring `template` makes it more consistent with actually ambiguous expressions IMHO. – dyp Jul 05 '14 at 20:45
  • OTOH, `template` can be added if it's not required, so this restriction can only be a simplification for implementers: they don't *have* to differentiate between potentially ambiguous and non-ambiguous expressions. – dyp Jul 05 '14 at 20:50
  • @dyp Do you mean that during the first phase, the compiler doesn't pay attention to the actual type of `Bar` while parsing `Foo`, so it can't easily determine whether or not it is dependent? This would seem to be a compelling reason why only direct members are accounted for in the specification. – Joseph Thomson Jul 05 '14 at 21:28
  • But still, `bar.baz` is not a dependent expression, so sticking `this->` or any expression in front of it whose type evaluates to the current instantiation should surely not be dependent either... Surely this would be consistent and fairly easy for compiler implementers to deal with (after all, can't `bar.baz` can be thought of as being prefixed with an implicit `this->`?) – Joseph Thomson Jul 05 '14 at 21:40
2

According to the standard § 14.2/4 Names of template specializations [temp.names]

When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template.

Edit:

Also, according the standard § 14.6.2.2/2 Type-dependent expressions [temp.dep.expr]:

this is type-dependent if the class type of the enclosing member function is dependent (14.6.2.1).

Thus, in order to call bar.baz<int>() via this you need to prefixed by the keyword template:

this->bar.template baz<int>();

LIVE DEMO

[Reason:] The compiler needs this "redantant" use of template keyword, because it can't decide whether the token < is operator< or the beginning of a template argument list.

101010
  • 41,839
  • 11
  • 94
  • 168
  • Thanks for the answer. However, it doesn't really get me any closer to understanding _why_ this is necessary, since that extract from the standard simply dictates that it shall be so without any explanation. Also, the wording is somewhat impenetrable, so I just have to take your word that this is what it's saying :P – Joseph Thomson Jul 05 '14 at 16:28
  • Regarding your edit, I get that that is generally why code like this is ambiguous, but I don't understand why it is only ambiguous when using `this->`. – Joseph Thomson Jul 05 '14 at 16:29
  • Your quote does not apply. The object expression `this->bar` of the _postfix-expression_ `this->bar.baz` is not type-dependent. – aschepler Jul 05 '14 at 16:50
  • @aschepler Isn't `this` a dependent expression if the class it refers to is a dependent type? – 101010 Jul 05 '14 at 18:09
  • I think I've just asked TemplateRex the same question, but why is `this` type-dependent? Or perhaps, why is the class type of a constructor dependent? I would have thought the class type would be unambiguous within the member function of a class template. – Joseph Thomson Jul 05 '14 at 19:25
  • 1
    @40two Yes, `this` is a dependent expression here. But 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." – aschepler Jul 05 '14 at 19:48