Skip to content

Instantly share code, notes, and snippets.

@vladiant
Created April 8, 2025 18:10
Show Gist options
  • Save vladiant/df98e5065b9705e6445eb5b2ceac5c06 to your computer and use it in GitHub Desktop.
Save vladiant/df98e5065b9705e6445eb5b2ceac5c06 to your computer and use it in GitHub Desktop.
C++26: variadic friends
// The base class
template<class Crtp, class MsgT>
class Receiver {
void receive(MsgT) {
static_cast<Crtp*>(this)->private_ += 1;
}
};
// The derived class
template<class MsgT>
struct Dispatcher :
public Receiver<Dispatcher<MsgT>, MsgT>
{
//_private member exposed to the base class, called Receiver
using Receiver<Dispatcher, MsgT>::Receiver;
friend Receiver<Dispatcher, MsgT>;
private:
int private_;
};
// The base class
template<class Crtp, class MsgT>
class Receiver {
void receive(MsgT) {
static_cast<Crtp*>(this)->private_ += 1;
}
};
// The derived class
template<class... MsgTs> // notice the variadic template parameters
struct Dispatcher :
public Receiver<Dispatcher<MsgTs...>, MsgTs>... // Inheritance supports pack expansion
{
using Receiver<Dispatcher, MsgTs>::Receiver...; // The using directive support pack expansion
friend Receiver<Dispatcher, MsgTs>...; // Error pre-C++26, accepted from C++26
private:
int private_;
};
// https://www.sandordargo.com/blog/2025/04/02/cpp26-variadic-friends
template<class T=void,
class U=void>
class Foo {
friend T;
friend U;
};
template<class... Ts>
class Foo {
friend Ts...;
};
template<class T>
class Passkey {
friend T;
Passkey() = default; // note that this ctor is private!
};
class A;
class B;
class C {
friend A;
private:
void internal();
public:
void intentionalA(Passkey<A>);
void intentionalB(Passkey<B>);
};
class A {
void m(C& c) {
c.internal(); // OK
c.intentionalA({}); // OK
c.intentionalB({}); // Error, Passkey<B>'s constructor is inaccessible
}
};
class B {
void m(C& c) {
c.intentionalB({}); // OK
}
};
template<class... T>
class Passkey {
friend T...;
Passkey() {}
};
class A;
class B;
class C {
friend A;
private:
void internal();
public:
void intentional(Passkey<A, B>);
};
class A {
void m(C& c) {
c.internal(); // OK
c.intentional({}); // OK
}
};
class B {
void m(C& c) {
c.intentional({}); // OK
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment