1. ホーム
  2. c++

[解決済み] ラムダのパラメータ型と戻り値の型を知ることは可能か?

2022-06-25 19:14:51

質問

ラムダが与えられたとき、そのパラメータの型と戻り値の型を把握することは可能ですか?もしそうなら、どのように?

基本的に、私は lambda_traits で、以下のような使い方ができます。

auto lambda = [](int i) { return long(i*10); };

lambda_traits<decltype(lambda)>::param_type  i; //i should be int
lambda_traits<decltype(lambda)>::return_type l; //l should be long

その動機は lambda_traits を使いたい、そして私は関数内部でそのパラメータ型と戻り値の型を知る必要がある、ということです。

template<typename TLambda>
void f(TLambda lambda)
{
   typedef typename lambda_traits<TLambda>::param_type  P;
   typedef typename lambda_traits<TLambda>::return_type R;

   std::function<R(P)> fun = lambda; //I want to do this!
   //...
}

とりあえず、ラムダは正確に1つの引数を取ると仮定してよいでしょう。

当初、私は std::function としています。

template<typename T>
A<T> f(std::function<bool(T)> fun)
{
   return A<T>(fun);
}

f([](int){return true;}); //error

しかし、これでは明らかにエラーになります。そこで、私はこれを TLambda のバージョンに変更し、関数テンプレートの std::function オブジェクトを構築したい場合(上図参照)。

どのように解決するのですか?

面白いことに、私はちょうど function_traits の実装を書きました。 に基づいて C++0x のラムダに対するテンプレートの特殊化 これは、パラメータの型を与えることができます。その質問の回答で説明されているように、トリックは decltype の中で、ラムダの operator() .

template <typename T>
struct function_traits
    : public function_traits<decltype(&T::operator())>
{};
// For generic types, directly use the result of the signature of its 'operator()'

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
    enum { arity = sizeof...(Args) };
    // arity is the number of arguments.

    typedef ReturnType result_type;

    template <size_t i>
    struct arg
    {
        typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
        // the i-th argument is equivalent to the i-th tuple element of a tuple
        // composed of those arguments.
    };
};

// test code below:
int main()
{
    auto lambda = [](int i) { return long(i*10); };

    typedef function_traits<decltype(lambda)> traits;

    static_assert(std::is_same<long, traits::result_type>::value, "err");
    static_assert(std::is_same<int, traits::arg<0>::type>::value, "err");

    return 0;
}

なお、この解決策 ではありません。 のような一般的なラムダには使えません。 [](auto x) {} .