CodeNebula
C++23coreexpert

Explicit This Parameter in Lambdas (Deducing This) (C++23 Addition)

C++23 · Completing Modern · Compiler flag: -std=c++23

Explanation

Lambdas can use an explicit `this` parameter, enabling recursive lambdas and `this` deduction.

Real-World Scenario

Write a recursive lambda to traverse a game’s scene graph.

Quick Snippet

snippet.cpp
auto factorial = [](this auto self, int n) { return n == 0 ? 1 : n * self(n - 1); };

Full Example

deducing_this.cpp
// CodeNebula - C++23 Example: Deducing This
// Compile: g++ -std=c++23 -Wall -Wextra -o example deducing_this.cpp
// Note: Requires GCC 14+ / Clang 18+ / MSVC 19.37+

// C++23 allows an explicit object parameter using "this auto& self",
// replacing CRTP patterns and simplifying overload sets for const/non-const.

#include <iostream>
#include <string>

struct TextBox {
    std::string text = "Hello, C++23!";

    // Single function replaces const and non-const overloads
    // 'self' deduces to TextBox& or const TextBox& based on call context
    auto&& get_text(this auto&& self) {
        std::cout << "  (called on "
                  << (std::is_const_v<std::remove_reference_t<decltype(self)>>
                      ? "const" : "mutable")
                  << " object)" << std::endl;
        return self.text;
    }

    // Recursive lambda-like pattern with explicit this
    void print_chars(this const TextBox& self) {
        std::cout << "Characters: ";
        for (char c : self.text) std::cout << c << ' ';
        std::cout << std::endl;
    }
};

// CRTP replacement: no template base class needed
struct Counter {
    int value = 0;

    // Chaining returns the derived type automatically
    auto& increment(this auto& self) {
        ++self.value;
        return self;
    }
};

struct NamedCounter : Counter {
    std::string name = "MyCounter";
};

int main() {
    std::cout << "=== Deducing This ===" << std::endl;

    TextBox box;
    std::cout << "Mutable access:" << std::endl;
    std::cout << "  text = " << box.get_text() << std::endl;

    const TextBox cbox;
    std::cout << "Const access:" << std::endl;
    std::cout << "  text = " << cbox.get_text() << std::endl;

    std::cout << "\n=== Recursive-style member ===" << std::endl;
    box.print_chars();

    std::cout << "\n=== CRTP Replacement ===" << std::endl;
    NamedCounter nc;
    nc.increment().increment().increment();
    std::cout << "NamedCounter '" << nc.name << "' value: " << nc.value << std::endl;

    return 0;
}

/*
Expected output:
=== Deducing This ===
Mutable access:
  (called on mutable object)
  text = Hello, C++23!
Const access:
  (called on const object)
  text = Hello, C++23!

=== Recursive-style member ===
Characters: H e l l o ,   C + + 2 3 !

=== CRTP Replacement ===
NamedCounter 'MyCounter' value: 3
*/
Run command
g++ -std=c++23 -Wall -Wextra -o example deducing_this.cpp