【一人 C++20 Advent Calendar 2019】状態を持たないラムダ式がデフォルト構築可能、代入可能となった【24日目】

一人 C++20 Advent Calendar 2019 24日目の記事になります。

状態を持たないラムダ式がデフォルト構築可能、代入可能となった

状態を持たないラムダ式がデフォルト構築可能、代入可能となりました。
次のようにラムダ式の型からオブジェクトを定義することができます。

#include <iostream>
#include <map>

int
main(){
    auto hello_world = [] {
        std::cout << "hello, world" << std::endl;
    };

    // lambda の型から新しいオブジェクトを生成できる
    decltype(hello_world) hello_world2{};
    hello_world2();

    // 状態を持っている(キャプチャしている)場合は生成できない
    auto hello_world3 = [&] {
        hello_world();
    };
    // NG
    // decltype(hello_world3) hello_world4{};

    return 0;
}
/*
output:
hello, world
*/

なるほど? これだけだと何が嬉しいんだと思いますよね。

こういう時に便利

std::map は第三テンプレート引数に比較型を渡すことができます。
これは通常は関数オブジェクト型を定義し、 operator () などで処理を記述する必要がありました。
しかし、ラムダ式がデフォルト構築可能になったことで次のようにテンプレート引数に対して直接処理を記述できるようになります。

#include <iostream>
#include <map>

int
main(){
    // std::map は第三テンプレート引数に比較型を渡すことができる
    // 本来は関数オブジェクトクラスを定義してテンプレート引数に渡す必要があった
    // これを delctype を経由して直接ラムダ式で処理を記述できるようになった
    auto data = std::map<
        int,
        char,
        decltype([](auto a, auto b) { return a > b; })
    > {
        { 1, 'A' }, { 11, 'J' }, { 12, 'Q' }, { 13, 'K' }
    };
    for(auto&& [key, value] : data){
        std::cout << key << ":" << value << std::endl;
    }
    

    return 0;
}
/*
output:
13:K
12:Q
11:J
1:A
*/

テンプレート引数に直接式を記述したい!!!!って C++11 の頃からずーーーーーっとやりたいと思っていてそんなことをするライブラリも自前でつくったりしていました。
C++20 だと delctype + ラムダ式で直接テンプレート引数に処理を記述できるようになるのでかなりメタプログラミングが捗りそうですね…これだよこれを待っていたんだよ!!!

対応コンパイラ

  • GCC 9
  • Clang 8.0

参照