我使用code from another answer来获取lambda函数的类型(return和arguments)。以下是答案中的相关代码:
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.
};
};
我想创建一个自动将lambda转换为函数指针的参数列表:
template<typename Func>
constexpr auto l2f(Func lambda) {
typedef function_traits<Func> traits;
return static_cast<traits::result_type(*)( ..all the args.. )(lambda);
}
现在我正在做的是,我在function_traits结构中添加了一个函数:
template <typename Func>
static auto convertToFunctionPointer(Func fn) {
return static_cast<ReturnType(*)(Args...)>(fn);
}
它有效,但我真正想知道的是如何在function_traits中提供Args的内容以从外部访问它,以及如何&#34;内联&#34;多个模板,然后展开它们。这样的事情(不起作用):
return static_cast<traits::result_type(*)(traits::arg<std::make_index_sequence<traits::arity>...>::type...)(lambda);
答案 0 :(得分:1)
作为Nawaz pointed out,并非所有lambda都可以转换为指针,只有那些没有捕获的指针。对于那些没有捕获的人,他们有一个隐含的转换,可以通过在前面添加+
来强制转换。
但是要直接回答你的问题,只需在特征中使用别名
template<typename C, typename R, typename... Args>
struct function_traits<R (C::*)(Args...)>
{
using signature = R(Args...);
};
template<typename F>
auto cast(F f)
{
return static_cast<typename function_traits<F>::signature*>(f);
}
答案 1 :(得分:0)
但我真正想知道的是如何在function_traits中提供Args的内容以从外部访问它,以及如何“内联”多个模板然后展开它们。
首先,我想到的解决您l2f()
特定问题的最简单的解决方案是将特定类型定义为PasserBy建议的signature
。
我提出了一个稍微不同的解决方案,但想法是一样的:你可以定义
using func_type = std::function<ReturnType(Args...)>;
所以l2f()
只是变成
template <typename Func>
constexpr auto l2f (Func lambda)
{ return static_cast<typename function_traits<Func>::func_type>(lambda); }
对于更一般的问题(“如何在function_traits中提供Args的内容以从外部访问它,以及如何”内联“多个模板然后展开它们”)我建议避免定义模板arg
结构只是在function_traits
using tuple_type = std::tuple<Args...>;
接下来,您必须调用辅助函数来转换arity
中function_traits
内的std::index_sequence
template <typename Func>
constexpr auto l2f (Func lambda)
{ return l2f_helper(lambda,
std::make_index_sequence<function_traits<Func>::arity>{}); }
并且辅助函数可以写为
template <typename Func, std::size_t ... Is>
constexpr auto l2f_helper (Func lambda,
std::index_sequence<Is...> const &)
{
return static_cast<std::function<
typename function_traits<Func>::result_type(
std::tuple_element_t<Is,
typename function_traits<Func>::tuple_type> ...)>>(lambda);
}
难看。我知道。
以下是完整的可编辑示例,其中包含l2f
和修改后的function_traits
两个版本。
#include <tuple>
#include <iostream>
#include <functional>
#include <type_traits>
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>
{
static constexpr std::size_t arity { sizeof...(Args) };
using result_type = ReturnType;
using func_type = std::function<ReturnType(Args...)>;
using tuple_type = std::tuple<Args...>;
};
template <typename Func>
constexpr auto l2f_v1 (Func lambda)
{ return static_cast<typename function_traits<Func>::func_type>(lambda); }
template <typename Func, std::size_t ... Is>
constexpr auto l2f_v2_helper (Func lambda,
std::index_sequence<Is...> const &)
{
return static_cast<std::function<
typename function_traits<Func>::result_type(
std::tuple_element_t<Is,
typename function_traits<Func>::tuple_type> ...)>>(lambda);
}
template <typename Func>
constexpr auto l2f_v2 (Func lambda)
{ return l2f_v2_helper(lambda,
std::make_index_sequence<function_traits<Func>::arity>{}); }
int main ()
{
auto f1 = l2f_v1([](int, long){ std::cout << "lambda1!" << std::endl; });
auto f2 = l2f_v2([](int, long){ std::cout << "lambda2!" << std::endl; });
f1(1, 2L);
f2(2, 3L);
static_assert( std::is_same<decltype(f1), decltype(f2)>{}, "!" );
}
稍微改进一下:如果您还在using
function_traits
模板
template <std::size_t I>
using a_type = std::tuple_element_t<I, tuple_type>;
辅助函数可以简化如下
template <typename Func, std::size_t ... Is>
constexpr auto l2f_helper (Func lambda,
std::index_sequence<Is...> const &)
{
return static_cast<std::function<
typename function_traits<Func>::result_type(
typename function_traits<Func>::template a_type<Is>...)>>(lambda);
}