How Deducing This Improves C++ Member Functions
Introduced in C++23, explicit object parameters—commonly referred to
as "deducing this"—fundamentally modernize how member
functions interact with the invoking object. By declaring the calling
instance explicitly as the function's first parameter, C++ resolves
long-standing design limitations. This feature eliminates redundant
boilerplate for const- and ref-qualified overloads, simplifies the
Curiously Recurring Template Pattern (CRTP), enables clean recursive
lambdas, and unlocks better compiler optimizations for passing small
objects by value.
Eliminating Duplicate Member Function Overloads
Before C++23, designing accessors that respect the value category of the host object often required up to four identical overloads: non-const lvalue reference, const lvalue reference, non-const rvalue reference, and const rvalue reference.
// Pre-C++23: Four distinct implementations
class Container {
std::vector<int> data;
public:
int& get() & { return data.front(); }
const int& get() const& { return data.front(); }
int&& get() && { return std::move(data).front(); }
const int&& get() const&&{ return std::move(data).front(); }
};With an explicit object parameter, a single templated function handles all value categories and qualifiers simultaneously. The compiler deduces the exact type and qualification of the calling instance:
// C++23: A single deduced member function
class Container {
std::vector<int> data;
public:
template <typename Self>
auto&& get(this Self&& self) {
return std::forward<Self>(self).data.front();
}
};This drastically reduces boilerplate, minimizes maintenance overhead, and ensures consistent behavior across accessors.
Simplifying the Curiously Recurring Template Pattern (CRTP)
The Curiously Recurring Template Pattern (CRTP) is traditionally used to achieve static polymorphism without the runtime overhead of virtual dispatch. Historically, this required the base class to be a template parameterized by the derived class:
// Pre-C++23 CRTP
template <typename Derived>
class Base {
public:
void interface() {
static_cast<Derived*>(this)->implementation();
}
};
class Derived : public Base<Derived> {
public:
void implementation();
};Deducing this removes the requirement for the base class
to be a template. The base class member function deduces the derived
type directly from the explicit parameter:
// C++23 Static Polymorphism
class Base {
public:
template <typename Self>
void interface(this Self&& self) {
self.implementation();
}
};
class Derived : public Base {
public:
void implementation();
};This pattern prevents template bloat, simplifies class hierarchies, and eliminates type-casting errors associated with mismatched template arguments.
Enabling Clean Recursive Lambdas
Because lambdas in C++ are translated into anonymous function
objects, they previously could not directly reference themselves inside
their own bodies without workarounds like std::function
(which incurs dynamic allocation and indirection overhead) or external
generic combinators.
An explicit object parameter allows a lambda to capture a reference to itself as its first argument:
auto factorial = [](this auto self, int n) -> int {
return (n <= 1) ? 1 : n * self(n - 1);
};This delivers efficient, fully inlined recursion with no heap allocation, dynamic overhead, or convoluted template wrappers.
Passing the this
Pointer by Value
Traditional member functions pass the calling object implicitly via a
pointer register (the this pointer). For small, trivially
copyable types like iterators, string views, or complex numbers, passing
by value in CPU registers is significantly faster than passing an
address via a pointer.
With explicit object parameters, functions can specify that the instance is passed by value:
struct Iterator {
int* ptr;
// Passed directly in a register rather than via a pointer
Iterator next(this Iterator self) {
++self.ptr;
return self;
}
};This gives developers fine-grained control over ABI calling conventions, enabling targeted micro-optimizations that were previously exclusive to free functions.