Cubbi 解释了为什么您的代码不起作用——lambda 不是函数指针。
现在,普通的 lambda 可以转换为函数指针。那么您是否真的想强制进行这种转换?
template<typename F>
struct as_pointer_t {
F f;
template<typename R, typename... Args>
operator type<R(*)(Args...)>() const { return {f}; }
template<typename R, typename... Args>
operator std::function<R(Args...)>() const { return (R(*)(Args...))f; }
};
template<typename F>
as_pointer_t<F> as_pointer( F&& f ) { return {std::forward<F>(f)}; }
现在我们可以这样做了:
int main() {
typedef int (*Myfun)(int);
std::function<int (int)> fn0(as_pointer([](int a)->int {
return -a;
}));
std::cout << "val == " << fn0(3) << std::endl; //"val == -3"
Myfun *fptr = fn0.target<Myfun>(); //fptr is no longer NULL!!
std::cout << "val == " << (*fptr)(3) << std::endl;
}
并且您的代码按预期工作。但是,只有当您的 lambda 没有捕获任何内容时,上述内容才会编译。
如果您的目标是将捕获的 lambda 转换为函数指针,则不能。您可以将状态存储在全局变量中,并在非捕获 lambda 中使用它。您还可以将捕获的 lambda 转换为函数指针和 void* 对。
我编写的代码采用编译时索引将void* 注入列表(以及使用可选类型而不是void*),并生成所述一对void* 和函数指针。一般情况很棘手——具体情况(比如第一个参数)要容易得多。
template<typename T> using type=T;
template<typename F, typename X=void*>
struct callback_t {
F f;
operator X() { return X(&f); }
template<typename R, typename...Args>
operator type<R(*)(X, Args...)>() const {
return []( X x, Args... args )->R {
F* f = (F*)(x);
return (*f)(std::forward<Args>(args)...);
};
}
};
template<typename X=void*, typename F>
callback_t<F,X> make_callback( F f ) {
return {std::forward<F>(f)};
}
使用:
typedef void(*pfun)(void*, int);
void call_pfun( pfun f, void* p) {
for (int i = 0; i < 3; ++i)
f( p, i );
}
int main()
{
int y = 7;
auto callback = make_callback([y]( int x ) { std::cout << x+y << "\n"; });
call_pfun( callback, callback );
}
live example.