Title
Disallow multiple friend-type-specifiers for a friend template
Status
review
Section
13.1 [temp.pre]
Submitter
Ambrose T

Created on 2024-04-30.00:00:00 last changed 2 months ago

Messages

Date: 2024-08-23.21:07:52

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.

Date: 2024-08-23.21:07:52

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 ]
Date: 2024-08-23.21:07:52

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.

Date: 2024-08-06.12:56:35

(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
  };
History
Date User Action Args
2024-08-23 21:07:52adminsetmessages: + msg7809
2024-08-17 07:39:11adminsetmessages: + msg7802
2024-08-17 07:39:11adminsetstatus: open -> review
2024-07-30 22:16:57adminsetmessages: + msg7779
2024-04-30 00:00:00admincreate