コンテンツにスキップ

💡 要約:C++20ラムダ式(前編):テンプレート構文と型制約、そしてC++23のdeducing thisがstd::functionなしで再帰ラムダを一行にする方法。

最終更新:2026-10-24

C++20 Lambda 式(前編)

C++20 における lambda テンプレート

C++14 は汎用ラムダ式をサポートしており、ラムダは任意の型の引数を受け取れます。例えば:

auto func = [](auto a, auto b) {
    return a + b;
};

これは次のように展開されます:

struct Func {
    template <typename T1, typename T2>
    auto operator()(T1 a, T2 b) const {
        return a + b;
    }
};

しかし、次のような展開形は実現できません:

1つ目:同じ型

template <class T>
auto operator()(T t1, T t2) const;

2つ目:std::array だけ

template <class T, std::size_t N>
auto operator()(std::array<T, N> const &) const; 

3つ目:推論なし

template <class T>
auto operator()() const;

C++14 のラムダは優れていますが、C++20 はこれらのケースを簡単に実現できるようにします。C++20 ではラムダ式の定義内でテンプレート型パラメータを使えます。基本構文は以下の通りです:

[]<typename T>(){}

以下、いくつかの例でその利点を説明します。

1.型の制限

次のような例で、C++14 では以下のコードを書けますが、使用時に渡されるものが vector とは限らず、期待される動作と不一致になり、エラーが発生する可能性があります。

auto print = [](auto vec) {
  for (auto x : vec) {
    std::cout << x << std::endl;
  }
};

C++20 以降、その型を制限できます:

auto print2 = []<typename T>(std::vector<T>& vec){
    //使用 std::vector<T> 执行操作
};

さて問題です。面接問題を出しましょう:C++14 で vector に制限するには、どうすれば安全を保証できるか知っていますか?

2.完全転送

C++20 では完全転送を非常に簡単に使えます。例えば:

auto lambdaFunc = []<typename T>(T&& number) {
  processFunction(std::forward<T>(number));
};

さて問題です。C++14 と比べてどんな利点がありますか?あるいは、C++14 で完全転送を実現するには何が必要でしょうか?

本節終わり

再帰ラムダとdeducing this(C++23)

素のラムダは自分自身を名指せないため、再帰には std::function に格納する(アロケーションと間接呼び出し)か、Yコンビネータで包む(賢いが読めない)かしかありませんでした。C++23の明示的オブジェクト引数——deducing thisと同じ機能——がこれを優雅に解決します。ラムダが自分自身を最初の引数として受け取ります:

// C++23 explicit object parameter: the lambda receives itself
auto factorial = [](this auto self, int n) -> long long {
    return n <= 1 ? 1 : n * self(n - 1);
};

static_assert(factorial(10) == 3628800);

// before C++23 you needed std::function (heavy) or a Y-combinator (clever)

self引数は呼び出しごとに推論されるため、ジェネリックな再帰も機能します。同じラムダが任意の型で再帰でき、二つのラムダが互いに自身を渡せば相互再帰も可能です。コンパイラはselfを透過的に見るため、これらの呼び出しは名前付き関数を書いたのと同じようにインライン化されます。

コンパイラ対応:GCC 14+、Clang 18+、MSVCはVS 2022 17.2から。-std=c++23でコンパイルしてください。

よくある質問

C++で再帰ラムダを書くには?

C++23以降は明示的オブジェクト引数を与えます:[](this auto self, int n) { ... self(n-1) ... }。それより前は std::function、Yコンビネータ、または素直に名前付き関数を使います。

deducing thisの再帰ラムダは通常の関数並みに速いですか?

実運用ではイエス:コンパイラはself経由の呼び出しを特殊化してインライン化でき、C++23以前に必須だった std::function の間接呼び出しとは違います。

deducing thisはジェネリックラムダでも使えますか?

はい。selfは呼び出しごとにauto&&推論されるため、同じラムダが異なる型で再帰でき、二つのラムダが互いに自身を渡せば相互再帰も実現できます。

関連トピック

コメント