C++0x VS 2010 中函数指针的 Lambda
我试图使用 lambda 来传递函数指针,但 VS2010 似乎无法转换它。我尝试过像这样使用 std::function ,但它崩溃了,我不知道我做得是否正确!
#include <windows.h>
#include <conio.h>
#include <functional>
#include <iostream>
#include <concrt.h>
void main()
{
std::function<void(void*)> f = [](void*) -> void
{
std::cout << "Hello\n";
};
Concurrency::CurrentScheduler::ScheduleTask(f.target<void(void*)>(), 0);
getch();
}
对我来说,编译器无法将这样的 lambda 转换为简单的函数指针似乎很奇怪,因为它没有捕获任何变量 - 即使它这样做了,我也想知道可以做什么。
每个 lambda 的类型是否唯一?因此,我可以使用 lambda 类型作为模板参数来修改模板函数,以生成一个可以调用的唯一静态函数,并希望对其进行优化?
已更新
以下内容似乎有效,但安全吗?
#include <windows.h>
#include <conio.h>
#include <iostream>
#include <concrt.h>
template<typename Signature>
struct Bind
{
static Signature method;
static void Call(void* parameter)
{
method(parameter);
}
};
template<typename Signature>
Signature Bind<Signature>::method;
template<typename Signature>
void ScheduleTask(Signature method)
{
Bind<Signature>::method = method;
Concurrency::CurrentScheduler::ScheduleTask(&Bind<Signature>::Call,0);
}
void main()
{
ScheduleTask
(
[](void*)
{
std::cout << "Hello";
}
);
ScheduleTask
(
[](void*)
{
std::cout << " there!\n";
}
);
getch();
}
再次更新
因此,在给定的帮助下,我想出了更短的方案:
template<typename Signature>
void (*LambdaBind(Signature))(void*)
{
struct Detail
{
static void Bind(void* parameter)
{
Signature method;
method(parameter);
}
};
return &Detail::Bind;
}
这可以用来将没有 void(*)(void*)
闭包的 lambda 包装成等效的函数指针。看来这在 VS2010 的更高版本中将变得不必要。
那么如何让它适用于带有闭包的 lambda 呢?
再次更新!
适用于 VS2010 中的闭包 - 不知道它是否“安全”...
template<typename Signature>
struct Detail2
{
static std::function<void(void*)> method;
static void Bind(void* parameter)
{
method(parameter);
}
};
template<typename Signature>
std::function<void(void*)> Detail2<Signature>::method;
template<typename Signature>
void (*LambdaBind2(Signature method))(void*)
{
Detail2<Signature>::method = method;
return &Detail2<Signature>::Bind;
}
I am trying to use a lambda to pass in place of a function pointer but VS2010 can't seem to convert it. I have tried using std::function like this and it crashes and I have no idea if I am doing this right!
#include <windows.h>
#include <conio.h>
#include <functional>
#include <iostream>
#include <concrt.h>
void main()
{
std::function<void(void*)> f = [](void*) -> void
{
std::cout << "Hello\n";
};
Concurrency::CurrentScheduler::ScheduleTask(f.target<void(void*)>(), 0);
getch();
}
It seems strange to me that the compiler can't convert such a lambda to a simple function pointer as it captures no variables - also in the case that it did I wonder what can be done.
Is the type of each lambda unique? So I could hack around with a template function using the lambdas' type as a template argument to generate a unique static function that could be called instead and hopefully optimised out?
UPDATED
The below seems to work but is it safe?
#include <windows.h>
#include <conio.h>
#include <iostream>
#include <concrt.h>
template<typename Signature>
struct Bind
{
static Signature method;
static void Call(void* parameter)
{
method(parameter);
}
};
template<typename Signature>
Signature Bind<Signature>::method;
template<typename Signature>
void ScheduleTask(Signature method)
{
Bind<Signature>::method = method;
Concurrency::CurrentScheduler::ScheduleTask(&Bind<Signature>::Call,0);
}
void main()
{
ScheduleTask
(
[](void*)
{
std::cout << "Hello";
}
);
ScheduleTask
(
[](void*)
{
std::cout << " there!\n";
}
);
getch();
}
UPDATED AGAIN
So with the help given I have come up with the shorter:
template<typename Signature>
void (*LambdaBind(Signature))(void*)
{
struct Detail
{
static void Bind(void* parameter)
{
Signature method;
method(parameter);
}
};
return &Detail::Bind;
}
This can be used to wrap a lambda with no closure of void(*)(void*)
into the equivalent function pointer. It appears that this will become unnecessary in a later version of VS2010.
So how to get this to work for a lambda with closures?
UPDATED AGAIN!
Works for closures in VS2010 - no idea if it's 'safe' though...
template<typename Signature>
struct Detail2
{
static std::function<void(void*)> method;
static void Bind(void* parameter)
{
method(parameter);
}
};
template<typename Signature>
std::function<void(void*)> Detail2<Signature>::method;
template<typename Signature>
void (*LambdaBind2(Signature method))(void*)
{
Detail2<Signature>::method = method;
return &Detail2<Signature>::Bind;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
lambda 的这个功能是在 VS2010 实现之后添加的,所以他们不尚不存在。
这是一个可能的通用解决方法,未经测试:
如果有任何部分令人困惑,请告诉我。
This feature of lambda's was added after VS2010 implemented them, so they don't exist in it yet.
Here's a possible generic work-around, very untested:
Let me know if any part is confusing.
如果您想要在 Concurrency::CurrentScheduler 中调度 lambda/函数对象,那么可能值得您查看 ConcRT Sample Pack v0.32 此处
task_scheduler 结构可以异步调度 lambda,但请注意,通过引用传递可能会导致不好的事情发生(因为我们正在讨论没有加入/等待的异步调度,堆栈上的引用在任务执行时可能不再有效!)
If scheduling lambdas/function objects in Concurrency::CurrentScheduler is what you want, it may be worth your while looking at ConcRT Sample Pack v0.32 here
The task_scheduler struct can schedule lambdas asynchronously, but be advised, passing by reference may cause bad things to happen (since we are talking about asynchronous scheduling without a join/wait, a reference on the stack may no longer be valid at time of task execution!)