关于c ++:如何从常规模板中提取lambda的返回类型和可变参数包

How to extract lambda's Return Type and Variadic Parameters Pack back from general template

我想创建一个接收lambda的模板化类或函数,并将其内部放入std :: function <>
Lambda可以具有任意数量的输入参数[](int a,float b,...)std :: function <>应对应于lambda的operator()的类型

1
2
3
4
5
6
7
8
9
10
11
template <typename T>
void getLambda(T t) {
   // typedef lambda_traits::ret_type RetType; ??
   // typedef lambda_traits::param_tuple --> somehow back to parameter pack Args...
   std::function<RetType(Args...)> fun(t);
}

int main() {
    int x = 0;
    getLambda([&x](int a, float b, Person c){});
}

所以我需要以某种方式提取返回类型和参数包

这里的答案建议对lambda的:: operator()使用部分规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template <typename T>
struct function_traits : public function_traits<decltype(&T::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.
    };
};

但是我需要一种将tuple <>转换回参数包的方法,以创建适当的std :: function <>实例化


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
// we specialize for pointers to member function
{
    using result_type = ReturnType;
    using arg_tuple = std::tuple<Args...>;
    static constexpr auto arity = sizeof...(Args);
};

template <class F, std::size_t ... Is, class T>
auto lambda_to_func_impl(F f, std::index_sequence<Is...>, T) {
    return std::function<typename T::result_type(std::tuple_element_t<Is, typename T::arg_tuple>...)>(f);
}

template <class F>
auto lambda_to_func(F f) {
    using traits = function_traits<F>;
    return lambda_to_func_impl(f, std::make_index_sequence<traits::arity>{}, traits{});
}

上面的代码应做您想要的。 如您所见,主要思想是创建一个整数包。 这是等距变量的非类型模板等效项。 我不知道可以使用这种包而不调用另一个函数的任何技术,因此通常在使用元组的情况下,您会看到一个嵌套的" impl"函数可以完成所有工作。 一旦有了整数包,就可以在访问元组时将其展开(也可以获取值)。

需要注意的是:使用using,而不是typename,尤其是在模板繁重的代码中,因为前者也可以为模板起别名。 并且不要在不使用空格的情况下使用enum技巧来存储静态值; 编译器将以任何方式对其进行优化,而使用static constexpr整数则更加清晰。