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

2024-11-11


2596. Instantiation of constrained non-template friends

Section: 13.9.2  [temp.inst]     Status: drafting     Submitter: David Friberg     Date: 2022-06-03

Consider:

  struct Base {};

  template<int N>
  struct S : public Base {
    friend int foo(Base&) requires (N == 1) { return 1; }
    friend int foo(Base&) requires (N == 2) { return 3; }
  };

  int main() {
    S<1> s1{};
    S<2> s2{};  // #1
  }

The current wording does not seem to cover what happens for this case. In particular, 13.9.2 [temp.inst] paragraph 17 does not cover constrained non-template friends.

See also the Itanium ABI issue 24.

Suggested resolution:

  1. Change in 13.7.5 [temp.friend] paragraph 9 as follows:

    A non-template friend declaration with a requires-clause shall be a definition. A friend function template with a constraint that depends on a template parameter from an enclosing template shall be a definition. Such a constrained friend function or function template declaration does not declare the same function or function template as a declaration in inhabiting any other scope.
  2. Change in 13.9.2 [temp.inst] paragraph 17 as follows:

    The type-constraints and requires-clause of a template specialization or member templated function are not instantiated along with the specialization or function itself, even for a member function of a local class; substitution into the atomic constraints formed from them is instead performed as specified in 13.5.3 [temp.constr.decl] and 13.5.2.3 [temp.constr.atomic] when determining whether the constraints are satisfied or as specified in 13.5.3 [temp.constr.decl] when comparing declarations.

    [ Note 7: ... ]

    [ Example 10: ... ]

    [ Example:

      struct Base {};
    
      template<int N>
      struct S : Base {
        friend int foo(Base&) requires (N == 1) { return 1; }  // #1
        friend int foo(Base&) requires (N == 2) { return 3; }  // #2
      };
      S<1> s1;
      S<2> s2;          // OK, no conflict between #1 and #2
      int x = foo(s1);  // OK, selects #1
      int y = foo(s2);  // OK, selects #2
    

    -- end example ]

    [ Example 11: ... ]

CWG 2022-11-10

The friend definitions should conflict with friend definitions from other instantiations of the same class template, consistent with how non-constrained friends would work. Note that the enclosing dependent class type does not appear in the friend function's signature, which is unusual.