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

2024-10-26


2917. Disallow multiple friend-type-specifiers for a friend template

Section: 13.1  [temp.pre]     Status: review     Submitter: Ambrose T     Date: 2024-07-30     Liaison: EWG

(From submissions #586 and #593.)

Consider:

struct C {
  template <typename>
  friend class Foo, int;
};

This is obviously nonsense, but is not prohibited by the wording.

Also consider:

  struct S {
    template <typename T>
    friend class Foo<T>::Nested;       // OK; see 13.7.5 [temp.friend] paragraph 5

    template <typename ...Ts>
    friend class Foo<Ts>::Nested...;   // makes no sense
  };

Suggested resolution (2024-07-30):

Change in 13.1 [temp.pre] paragraph 5 as follows:

In a template-declaration, explicit specialization, or explicit instantiation, the init-declarator-list in the declaration shall contain at most one declarator. When such a declaration is used to declare a class template, no declarator is permitted. In a template-declaration whose declaration is a friend-type-declaration, the friend-type-specifier-list shall consist of exactly one friend-type-specifier; if it is a pack expansion (13.7.4 [temp.variadic]), any packs expanded by that pack expansion shall not have been introduced by the template-declaration. [ Example:
template<class ...>
struct C {
  struct Nested { };
};

template<class ... Us>
struct S {
  template <typename ...Ts>
  friend class C<Ts>::Nested...;     // error
  friend class C<Us>::Nested...;     // OK
};
-- end example ]

The above resolution allows the following example:

  template<class ... Us>
  struct S {
   template<class T>
   friend class C<T, Us>::Nested...;
  };

CWG was not convinced the above example was intended to be supported by paper P2893R3, which introduced pack expansions for friend declarations.

Proposed resolution (2024-08-16):

(This is not a DR.)

(Issue 2862 modifies the same paragraph.)

Change in 13.1 [temp.pre] paragraph 5 as follows:

In a template-declaration, explicit specialization, or explicit instantiation, the init-declarator-list in the declaration shall contain at most one declarator. When such a declaration is used to declare a class template, no declarator is permitted. In a template-declaration whose declaration is a friend-type-declaration, the friend-type-specifier-list shall consist of exactly one friend-type-specifier that is not a pack expansion. [ Example:
template<class ...>
struct C {
  struct Nested { };
};

template<class ... Us>
struct S {
  template <typename ...Ts>
  friend class C<Ts>::Nested...;     // error
  friend class C<Us>::Nested...;     // OK
};
-- end example ]

CWG 2024-08-16

The proposed resolution above disallows a few examples from paper P2893R3 (Variadic friends), such as

  template<class... Ts>
  struct VS {
    template<class U>
    friend class C<Ts>::Nested...; // now ill-formed
  };

The adopted wording for P2893R3 makes the friend-type-specifier (not the entire template-declaration) the pattern that is expanded by the pack expansion, leading to the expansion

  struct VS<T1, T2, T3> {
    template<class U>
    friend class C<T1>::Nested, class C<T2>::Nested, class C<T3>::Nested;
  };

However, that violates the principle that a template-declaration declares exactly one entity (see issue 2862).

As an aside, the paper as adopted misrepresents the status of members of dependent types, which are covered by 13.7.5 [temp.friend] paragraph 5.

CWG welcomes a paper making the template friend cases valid, but such a facility would appear to require substantial changes to the normative wording, which a core issue is not equipped for.

CWG asks EWG to consent to the reduction in scope for the variadic friends facility, via paper issue cplusplus/papers#2032.