我有以下代码:
#include <functional>
//...
typedef int (*Myfun)(int);
std::function<int (int)> fn0([](int a)->int {
return -a;
});
std::cout << "val == " << fn0(3) << std::endl; //"val == -3"
Myfun *fptr = fn0.target<Myfun>(); //fptr is NULL!!
std::cout << "val == " << (*fptr)(3) << std::endl; //Access violation error
实际上,这段代码是来自MSDN的代码,有一点变化:使用lambda而不是普通函数。
为什么调用fn0.target<Myfun>()
返回NULL?
当我声明一个常规函数
int neg(int val) {
return (-val);
}
和写std::function<int (int)> fn0(neg);
,一切似乎都工作,但lambda没有正确处理。
typedef int (*Myfun)(int);
中的Myfun
类型与函数目标的类型无关,后者是通过执行表达式[](int a)->int { return -a; }
产生的闭包对象的唯一未命名类型
试着执行std::cout << fn0.target_type().name() << 'n';
自己看看。
当你用int neg(int val) { return (-val); }
声明一个函数时,neg
的类型恰好是Myfun
(在函数到指针的转换之后,这发生在std::function<int(int)> fn0(neg)
中),这就是为什么std::function::target()
能够返回一个指向它的指针。
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 );
}
生活例子。