2014-09-30

C++14の新機能: ジェネリックlambda

C++14に追加された新機能に、ジェネリックlambdaがある。

lambda式は便利だ。lambda式が便利な理由は、簡潔に書けるからだ。しかし、C++11のlambda式は、引数の型を書かなければならないので、十分に簡潔に書くことはできない。

struct very_long_name
{
    int x ;
    double y ;
    std::string z ;
} ;

void sort( std::vector<very_long_name> & v )
{
    std::sort( v.begin(), v.end(),
        []( very_long_name & a, very_long_name & b )
        {   // 複数のデータメンバーを正しく比較する方法を覚えておくと、
            // いつかためになる。
            return std::tie( a.x, a.y, a.z ) < std::tie( b.x, b.y, b.z ) ;
        } ) ;
}

引数の型ぐらい、コンパイラーが何とかしてほしいものである。そこで、C++14には、引数の型を書かずにすむ、ジェネリックlambdaが追加された。

    std::sort( v.begin(), v.end(),
        []( auto & a, auto & b )
        {
            return std::tie( a.x, a.y, a.z ) < std::tie( b.x, b.y, b.z ) ;
        } ) ;

これだけでは、単に引数の型を省略出来るだけに見えるかもしれない。以下の例で、ジェネリックlambdaの素晴らしさがわかるだろう。

template < typename print >
void f( print p )
{
    p( 42 ) ;
    p( 3.14 ) ;
    p( "hello" ) ;
}

int main()
{
    f( []( auto && elem ) { std::cout << elem << '\n' ; } ) ;
}

ジェネリックlambdaは、テンプレートのようにどんな型でも受け付ける。

lambda式は魔法ではなく、クロージャーオブジェクトと呼ばれる、単なる関数オブジェクトを返すシンタックスシュガーに過ぎない。ジェレリックlambda式も同じだ。テンプレートのようにと書いたが、実際、メンバーテンプレートを持つ関数オブジェクトのシンタックスシュガーに過ぎない。例えば、上記のlambda式によって生成されるクロージャーオブジェクトは、以下のようになる。


struct closure_object
{
    template < typename T >
    void operator ( T && elem ) const
    { std::cout << elem << '\n' ; }
} ;

メンバーテンプレートを使えば、printに与える適切な関数オブジェクトを記述することができるが、C++11のlambda式には、これを可能にする文法がなかった。C++14で、ジェネリックlambdaとして追加された。

なおこの機能はGCC 4.9とClang 3.4で実装されている。

Clang - C++1z, C++14, C++11 and C++98 Status

C++1y/C++14 Support in GCC - GNU Project - Free Software Foundation (FSF)

See Also:

本の虫: C++14の新機能: 2進数リテラル

本の虫: C++14の新機能: decltype(auto)

本の虫: C++14の新機能: 関数の戻り値の型推定

本の虫: C++14の新機能: 初期化lambdaキャプチャー

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

次の論文集がでるのは10月半ばになるので、それまではC++の解説記事を書く。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2 comments:

Anonymous said...

std::tieは勉強になりました。
自分、クイックソートを理解してないので手書きで書けないんですよね。いつもバブルソートで逃げてます。
しかし、これからはtieがあるので逃げずに済みそうです。
10月の論文もよろしくお願いします。
自分の一次ソースここですから。

Anonymous said...

ジェネリックでキャプチャしないlambda式を関数ポインタに変換するにはどうすれば良いのでしょうか?