Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Name lookup in template base: why do we add this->

Consider the following:

struct Base {
    void foo();
};

template <class T>
struct Derived : Base {
    void bar() {
        this->foo();
    }
};

Typically, we explain that this-> makes foo() a dependent name, so its lookup is posponed to the second phase, i.e. to the template instantiation point.

But the second phase lookup invokes only ADL, which does not consider member functions, does it?

I'd appreciate any pointer to the Standard paragraph that explains why the above code compiles.

like image 861
Igor R. Avatar asked Dec 22 '22 20:12

Igor R.


1 Answers

But the second phase lookup invokes only ADL, which does not consider member functions, does it?

It does not. However ADL adds to the lookup set, it does not comprise all of it. Also, the idea you are paraphrasing here applies to a postfix-expression in postfix-expression(args), when said postfix-expression is an unqualified-id.

[temp.dep]

1 ... In an expression of the form:

postfix-expression ( expression-listopt )

where the postfix-expression is an unqualified-id, the unqualified-id denotes a dependent name if

  • [... specific conditions ...]

If an operand of an operator is a type-dependent expression, the operator also denotes a dependent name. Such names are unbound and are looked up at the point of the template instantiation ([temp.point]) in both the context of the template definition and the context of the point of instantiation.

So if you had there foo() instead, lookup would not consider members, and would instead try only free functions, both at the point of definition and instantiation (where ADL can add to the lookup set, assuming we had a dependent expression).

But for this->foo (I omitted the call intentionally, to discuss the postfix-expression), we have class member access. And here other paragraphs apply:

[temp.dep.type]

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

  • [...]
  • 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. [ Note: If no such member is found, and the current instantiation has any dependent base classes, then the id-expression is a member of an unknown specialization; see below.  — end note ]

6 A name is a member of an unknown specialization if it is

  • [...]
  • An id-expression denoting the member in a class member access expression in which either
    • the type of the object expression is the current instantiation, the current instantiation has at least one dependent base class, and name lookup of the id-expression does not find a member of a class that is the current instantiation or a non-dependent base class thereof; or

7 Similarly, if the id-expression in a class member access expression for which the type of the object expression is the current instantiation does not refer to a member of the current instantiation or a member of an unknown specialization, the program is ill-formed even if the template containing the member access expression is not instantiated; no diagnostic required.

These bullets tell us what lookup to perform when this->foo is encountered. It looks up members only. In our case, we have a non-dependent base class in the current instantiation, so that's where the member is to be found, unambiguously.

Having found the member function, the postfix-expression this->foo denotes a callable, and that is how the function call is resolved.

like image 180
StoryTeller - Unslander Monica Avatar answered Jan 09 '23 11:01

StoryTeller - Unslander Monica