lambda expression を 関数ポインタ型へと変換する

さて、キャプチャを行なっていないラムダ式は次のように関数ポインタ型へと型変換を行うことが出来ます。

auto f = [](int){ return 0; };
std::common_type<int(*)(int)>::type ff = f;


このような場合は問題ないのですが、例えば次のようにテンプレート型を使って関数ポインタ型として関数で受け取りたい場合にエラーになってしまいます。

// 関数ポインタ型から型推論して、戻り値型を返すメタ関数
template<typename Result, typename ...Args>
Result
result_type(Result(*)(Args...));

int
plus(int, int);

// ok
static_assert(std::is_same<decltype(result_type(&plus)), int>{}, "");


auto f = [](int){ return 0; };

// error : result_type 関数で受け取る事が出来ない。
static_assert(std::is_same<decltype(result_type(f)), int>{}, "");


この場合は、static_cast を行うことで回避もできますが、いちいち型を書くのはめんどくさいです。

// error
static_assert(std::is_same<decltype(result_type(f)), int>{}, "");

// ok
static_assert(std::is_same<decltype(result_type(static_cast<int(*)(int)>(f))), int>{}, "");


と、いうことでラムダ式を受け取って関数ポインタ型へと変換して返すようなヘルパ関数を書いてみました。

[ソース]

#include <type_traits>


template<typename Func, typename T, typename Result, typename ...Args>
typename std::common_type<Result(*)(Args...)>::type
lambda_to_function(Result(T::*)(Args...) const, Func func){
    return func;
}

template<typename Func>
auto
lambda_to_function(Func func)
->decltype(lambda_to_function(&decltype(func)::operator(), func)){
    return lambda_to_function(&decltype(func)::operator(), func);
}


template<typename Result, typename ...Args>
Result
result_type(Result(*)(Args...));

int
plus(int, int);

int
main(){
    static_assert(std::is_same<decltype(result_type(&plus)), int>{}, "");

    auto f = [](int){ return 0; };
    static_assert(std::is_same<decltype(result_type(lambda_to_function(f))), int>{}, "");

    auto ff = [](int, int, int){};
    static_assert(std::is_same<decltype(result_type(lambda_to_function(ff))), void>{}, "");

    return 0;
}


decltype([]{})::operator() から型推論を行っています。
こんな事できたんですね…。