On Wed, May 7, 2025 at 11:12 AM Frederick Virchanza Gotham via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On Wed, May 7, 2025 at 2:44 AM Arthur O'Dwyer wrote:
>
> There is; check out the "passkey idiom."
> https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2893r3.html#passkey-idiom

I read your paper just now. I wonder had you considered excluding
certain classes with a 'requires' clause? Let's say you only want to
be friends with classes that have a 'value' that is a pointer to a
polymorphic class.  So where you had:

    template<class... Ts>
    class Foo {
      friend Ts...;
    };

Imagine if you could have:

    template<class... Ts>
    class Foo {
      (friend Ts requires (is_pointer_v< Ts::value > &&
is_polymorphic_v< remove_pointer_t<Ts::value> >) ). . . ;
    };

Something along those lines.

That thing with the parentheses isn't remotely how C++'s declaration grammar works, though, so, no.

It might be plausible to befriend a bunch of template specializations by pretending to befriend an explicit specialization or partial specialization, like this:

template<class> struct A;
class B {
  static int f();
  template<> friend struct A<int>;  // invalid today, but hypothetically this could become legal
  template<class T> requires (sizeof(T) == 1) friend struct A<T>;  // invalid today, but hypothetically this could become legal
};
template<> struct A<int> {
  static int g(B *b) { return b->f(); }  // hypothetically, this would become accessible
};
template<> struct A<char> {
  static int g(B *b) { return b->f(); }  // even more hypothetically, this would become accessible (even though the befriender used partial-specialization syntax and this is an explicit specialization)
};
template<> struct A<short> {
  static int g(B *b) { return b->f(); }  // remains ill-formed because B::f is inaccessible to this specialization
};

But that has nothing to do with "variadic friend"; that would be a completely different feature, completely different syntax.

–Arthur