我有以下代码可以将lambda转换为C样式的函数指针。这适用于所有lambda,包括具有捕获功能的lambda。
#include <iostream>
#include <type_traits>
#include <utility>
template <typename Lambda>
struct lambda_traits : lambda_traits<decltype(&Lambda::operator())>
{};
template <typename Lambda, typename Return, typename... Args>
struct lambda_traits<Return(Lambda::*)(Args...)> : lambda_traits<Return(Lambda::*)(Args...) const>
{};
template <typename Lambda, typename Return, typename... Args>
struct lambda_traits<Return(Lambda::*)(Args...) const>
{
using pointer = typename std::add_pointer<Return(Args...)>::type;
static pointer to_pointer(Lambda&& lambda)
{
static Lambda static_lambda = std::forward<Lambda>(lambda);
return [](Args... args){
return static_lambda(std::forward<Args>(args)...);
};
}
};
template <typename Lambda>
inline typename lambda_traits<Lambda>::pointer to_pointer(Lambda&& lambda)
{
return lambda_traits<Lambda>::to_pointer(std::forward<Lambda>(lambda));
}
可以使用以下方法将带有捕获的lambda传递到C风格的API中:
// Function that takes a C-style function pointer as an argument
void call_function(void(*function)())
{
(*function)();
}
int main()
{
int x = 42;
// Pass the lambda to the C-style API
// This works even though the lambda captures 'x'!
call_function(to_pointer([x] {
std::cout << x << std::endl;
}));
}
鉴于此,编写一个类似的模板可以将lambda(包括带有捕获的lambda)一般地转换为std::function
对象似乎相对简单,但是我在努力寻找方法。(我对模板元编程技术不是很熟悉,所以我有点迷路了)
这是我尝试过的,但是无法编译:
template <typename Lambda>
struct lambda_traits : lambda_traits<decltype(&Lambda::operator())>
{};
template <typename Lambda, typename Return, typename... Args>
struct lambda_traits<typename std::function<Return(Args...)>> : lambda_traits<typename std::function<Return(Args...)> const>
{};
template <typename Lambda, typename Return, typename... Args>
struct lambda_traits<typename std::function<Return(Args...)> const>
{
using pointer = typename std::function<Return(Args...)>*;
static pointer to_pointer(Lambda&& lambda)
{
static Lambda static_lambda = std::forward<Lambda>(lambda);
return [](Args... args) {
return static_lambda(std::forward<Args>(args)...);
};
}
};
template <typename Lambda>
inline typename lambda_traits<Lambda>::pointer to_pointer(Lambda&& lambda)
{
return lambda_traits<Lambda>::to_pointer(std::forward<Lambda>(lambda));
}
这无法编译,并表示Lambda
部分专门化未使用template参数。
正确的方法是什么?
(请注意,我一直使用兼容C ++ 11的编译器,因此C ++ 14及更高版本的功能不可用)
如果要在std::function
不指定的签名的情况下将可调用对象转换为std::function
,则这正是C ++ 17的推论指南std::function
所针对的。我们只需要为C ++ 11实现一个版本即可。注意,这仅适用于非重载的可调用对象operator()
;否则,将无法执行此操作。
#include <functional>
#include <utility> // std::declval
// Using these functions just for the return types, so they don't need an implementation.
// Support function pointers
template <typename R, typename... ArgTypes>
auto deduce_std_function(R(*)(ArgTypes...)) -> std::function<R(ArgTypes...)>;
// Support callables (note the _impl on the name).
// Many overloads of this to support different const qualifiers and
// ref qualifiers. Technically should also support volatile, but that
// doubles the number of overloads and isn't needed for this illustration.
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...)) -> std::function<R(ArgTypes...)>;
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) const) -> std::function<R(ArgTypes...)>;
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) &) -> std::function<R(ArgTypes...)>;
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) const&) -> std::function<R(ArgTypes...)>;
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) &&) -> std::function<R(ArgTypes...)>;
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) const&&) -> std::function<R(ArgTypes...)>;
// To deduce the function type for a callable, get its operator() and pass that to
// the _impl functions above.
template <typename Function>
auto deduce_std_function(Function)
-> decltype(deduce_std_function_impl(&Function::operator()));
template <typename Function>
using deduce_std_function_t = decltype(deduce_std_function(std::declval<Function>()));
template <typename F>
auto to_std_function(F&& fn) -> deduce_std_function_t<F> {
return deduce_std_function_t<F>(std::forward<F>(fn));
}
我们需要推导的函数类型std::function<...>
。因此,我们需要实现某种deduce_std_function
确定功能类型的方法。有几种方法可以实现此目的:
function_traits
输入一个可以为我们确定功能类型的类型(类似于您的lambda_traits
)。deduce_std_function
为重载集,其中重载的返回类型是推导类型。我之所以选择后者,是因为它模仿了演绎指南。前者也可以,但是我认为这种方法可能更简单(函数样板比结构样板小)。
查看有关std::function
演绎指南的文档,有一个简单的方法:
template<class R, class... ArgTypes> function(R(*)(ArgTypes...)) -> function<R(ArgTypes...)>;
这很容易翻译:
template <typename R, typename... ArgTypes>
auto deduce_std_function(R(*)(ArgTypes...)) -> std::function<R(ArgTypes...)>;
基本上,给定任何函数指针R(*)(ArgTypes...)
,我们想要的类型是std::function<R(ArgTypes...)>
。
文档指出第二种情况是:
对于某些类类型G,如果
&F::operator()
将重载视为未经评估的操作数时decltype(&F::operator())
格式正确且形式为R(G::*)(A...)
(可选cv限定,可选noexcept,可选为左值引用限定),则此重载仅参与重载解析std::function<R(A...)>
。
满嘴 但是,这里的关键思想是:
decltype(&F::operator())
具有以下形式R(G::*)(A...)
:std::function<R(A...)>
”这意味着我们需要获取指向成员函数的指针,operator()
并将该指向成员函数的签名用作的签名std::function
。
那是从哪里来的:
template <typename Function>
auto deduce_std_function(Function)
-> decltype(deduce_std_function_impl(&Function::operator()));
我们之所以委托,deduce_std_function_impl
是因为我们需要推断出指向member-member-function的签名&Function::operator()
。
该impl函数有趣的重载为:
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...)) -> std::function<R(ArgTypes...)>;
简而言之,我们获取了R ... (ArgTypes...)
指向成员函数指针的签名(位)并将其用于std::function
。语法的其余部分(该(F::*)
位)仅是指向成员函数指针的语法。R(F::*)(ArgTypes...)
是F
具有签名R(ArgTypes...)
且没有const,volatile或reference限定符的类的指向成员函数的指针的类型。
可是等等!我们要支持const和reference限定符(您可能还希望增加对volatile的支持)。因此,我们需要deduce_std_function_impl
对每个限定符重复以上内容:
签名 | 类声明 |
---|---|
R(F::*)(ArgTypes...) |
void operator()(); |
R(F::*)(ArgTypes...) const |
void operator()() const; |
R(F::*)(ArgTypes...) & |
void operator()() &; |
R(F::*)(ArgTypes...) const& |
void operator()() const&; |
R(F::*)(ArgTypes...) && |
void operator()() &&; |
R(F::*)(ArgTypes...) const&& |
void operator()() const&&; |
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句