This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115f. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-12-06


1321. Equivalency of dependent calls

Section: 13.7.7.2  [temp.over.link]     Status: CD3     Submitter: Jason Merrill     Date: 2011-05-18

[Moved to DR at the October, 2012 meeting.]

Consider the following example:

  int g(int);

  template <class T> decltype(g(T())) f();

  int g();

  template <class T> decltype(g(T())) f() { return g(T()); }

  int i = f<int>();

Do the two fs declare the same function template? According to 13.7.7.2 [temp.over.link] paragraph 5,

Two expressions involving template parameters are considered equivalent if two function definitions containing the expressions would satisfy the one definition rule (6.3 [basic.def.odr]), except that the tokens used to name the template parameters may differ as long as a token used to name a template parameter in one expression is replaced by another token that names the same template parameter in the other expression.

The relevant portion of 6.3 [basic.def.odr] paragraph 5 says,

in each definition of D, corresponding names, looked up according to 6.5 [basic.lookup], shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution (12.2 [over.match]) and after matching of partial template specialization (13.10.4 [temp.over]), except that a name can refer to a const object with internal or no linkage if the object has the same literal type in all definitions of D, and the object is initialized with a constant expression (7.7 [expr.const]), and the value (but not the address) of the object is used, and the object has the same value in all definitions of D

This could be read either way, since overload resolution isn't done at this point. Either we consider the result of the unqualified name lookup and say that the expressions aren't equivalent or we need a new rule for equivalence and merging of dependent calls.

Proposed resolution (December, 2011):

  1. Change 13.7.7.2 [temp.over.link] paragraph 5 as follows:

  2. Two expressions involving template parameters are considered equivalent if two function definitions containing the expressions would satisfy the one definition rule (6.3 [basic.def.odr]), except that the tokens used to name the template parameters may differ as long as a token used to name a template parameter in one expression is replaced by another token that names the same template parameter in the other expression. For determining whether two dependent names (13.8.3 [temp.dep]) are equivalent, only the name itself is considered, not the result of name lookup in the context of the template. If multiple declarations of the same function template differ in the result of this name lookup, the result for the first declaration is used. [Example:

      template <int I, int J> void f(A<I+J>); // #1
      template <int K, int L> void f(A<K+L>); // same as #1
    
      template <class T> decltype(g(T())) h();
      int g(int);
      template <class T> decltype(g(T())) h() // redeclaration of h() uses the earlier lookup
        { return g(T()); }                    // ...although the lookup here does find g(int)
      int i = h<int>();                       // template argument substitution fails; g(int)
                                              // was not in scope at the first declaration of h()
    

    end example] Two expressions...

  3. Change 13.8.3 [temp.dep] paragraph 1 as follows:

  4. ...In an expression of the form:

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

    if an operand...

  5. Change 13.8.4.2 [temp.dep.candidate] paragraph 1 as follows:

  6. For a function call that depends on a template parameter where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules (6.5.3 [basic.lookup.unqual], 6.5.4 [basic.lookup.argdep], 6.5.5 [basic.lookup.qual]) except that:

    If the function name is an unqualified-id and the call would be ill-formed or would find a better match had the lookup within the associated namespaces considered all the function declarations with external linkage introduced in those namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation contexts, then the program has undefined behavior.