最終更新日時:
が更新

履歴 編集

ジェネリックラムダ(C++14)

概要

ジェネリックラムダ(generic lambdas)は、C++11のラムダ式を拡張して、パラメータにテンプレートを使用できるようにした機能である。

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

このラムダ式は、以下のような関数呼び出し演算子を持つ関数オブジェクトを生成する。

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

仕様

  • ラムダ式のパラメータには、具体的な型に加えて、autoを指定できる。
  • autoは、型をテンプレートパラメータにするためのプレースホルダーである。
  • ラムダ式のパラメータにautoを指定し、[](auto x) {}のように記述した場合、以下のような関数オブジェクトが生成される:

    struct F {
      template <class T>
      auto operator()(T x) const {}
    };
    

  • 複数のパラメータ型をそれぞれautoに指定した場合、各パラメータは異なるテンプレートパラメータが割り当てられる:

    auto f = [](auto a, auto b) {}
    

    struct F {
      template <class T1, class T2>
      auto operator()(T1 a, T2 b) const {}
    };
    

  • ラムダ式に指定するautoは、テンプレートと同様に、constvolatile、参照、ポインタといった修飾ができる:

    auto plus = [](const auto& a, const auto& b) { return a + b; };
    

  • 関数テンプレートと違い、ラムダ式のautoパラメータは、パラメータのテンプレートパラメータを推論する目的には使用できない:

    auto f = [](std::vector<auto> a) {}; // コンパイルエラー
    

  • キャプチャを含まないジェネリックラムダは、関数ポインタへの変換演算子を持つ。変換先の関数ポインタは、パラメータ型を推論した結果のラムダ式のシグニチャと、完全に一致しなければならない:

    int(*fp1)(int) = [](auto x) { return x; }; // OK
    char(*fp2)(int) = [](auto x) { return x; }; // コンパイルエラー
    

備考

ジェネリックラムダはパラメータの型がテンプレートであるために、パラメータをテンプレートのままstd::functionクラスのオブジェクトに代入はできない。

#include <iostream>
#include <string>

using namespace std::string_literals;

int main()
{
  // ラムダ式のパラメータ型をautoにすることで、
  // 任意の型をパラメータとして受け取れる
  auto plus = [](auto a, auto b) { return a + b; };

  int result1 = plus(3, 2);
  std::string result2 = plus("Hello"s, "World"s);

  std::cout << result1 << std::endl;
  std::cout << result2 << std::endl;
}

出力

5
HelloWorld

検討されたほかの選択肢

ジェネリックラムダの構文として、最初はautoを書かずにパラメータの変数名と型修飾のみを書くように考えられていた。

[](const& x, & y) { return x + y; }

これが現在autoを書くようになったのは、可読性のためである。

関連項目

参照