我有以下代码:
#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没有得到正确处理。
答案 0 :(得分:5)
Myfun
中的typedef int (*Myfun)(int);
类型与函数的目标类型无关,该函数的目标是通过执行表达式{{1}生成的闭包对象的唯一,未命名类型}}
尝试执行[](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)
能够返回指针的原因。
答案 1 :(得分:1)
Cubbi解释了为什么你的代码不起作用 - lambda不是函数指针。
现在,普通的lambdas可以转换为函数指针。所以你认为你真的想强制转换?
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*
),并生成{{1}对的代码和函数指针。一般情况很棘手 - 具体案例(比如第一个论点)要容易得多。
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)};
}