Spelling the type of a “self” parameter with Reflection

Over on std-proposals, it was pointed out that using C++23 “explicit object parameter” syntax without using auto (since auto makes your member function into a template, changing its semantics) is sometimes cumbersome:

struct MyLengthilyNamedClass {
  int i_;
  int f(this MyLengthilyNamedClass self) { return self.i_; }
};

You can shorten each member function declaration at the expense of some repetitive boilerplate up front:

struct MyLengthilyNamedClass {
  using Self = MyLengthilyNamedClass;
  int i_;
  int f(this Self self) { return self.i_; }
};

Sebastian Wittmeier observes that we can eliminate that boilerplate’s error-prone repetition of the class name MyLengthilyNamedClass by using C++26 Reflection:

struct MyLengthilyNamedClass {
  using Self = [: std::meta::current_class() :];
  int i_;
  int f(this Self self) { return self.i_; }
};

Thibault Ricord-Marchal observes that because the values of defaulted template arguments are evaluated in the context of the “caller,” rather than where they appear lexically, we can even factor out that boilerplate to the top level:

template<std::meta::info R = std::meta::current_class()>
using Self = [: R :];

struct MyLengthilyNamedClass {
  int i_;
  int f(this Self<> self) { return self.i_; }
};

Now, in these toy examples, I see no reason to prefer any of the above snippets over the simple idiomatic implicit-object-parameter member function we’ve been writing since the dawn of time:

struct MyLengthilyNamedClass {
  int i_;
  int f() const { return i_; }
};

But notice the difference in calling convention. Our first four snippets pass self by value, while the ordinary f() const needs to do a memory load through the this pointer. I could just barely imagine a situation where that cost mattered. (Godbolt.)


I imagine one might find other uses for Self<>. Off the top of my head, it provides a way to shorten some of the boilerplate of special member functions:

struct MyLengthilyNamedClass {
  MyLengthilyNamedClass(const MyLengthilyNamedClass&) = default;
  MyLengthilyNamedClass& operator=(const MyLengthilyNamedClass&) = default;
};

P2952, coming soon to C++29, will permit auto’ing the assignment operator’s return type:

struct MyLengthilyNamedClass {
  MyLengthilyNamedClass(const MyLengthilyNamedClass&) = default;
  auto& operator=(const MyLengthilyNamedClass&) = default;
};

But with Self<>, you could shorten fully three of the four repetitions (Godbolt):

struct MyLengthilyNamedClass {
  MyLengthilyNamedClass(const Self<>&) = default;
  Self<>& operator=(const Self<>&) = default;
};

I wouldn’t want to see that in my own codebases. But it’s an idea.

Posted 2026-09-15