C ++ 0x Lambda到VS 2010中的函数指针 [英] C++0x Lambda to function pointer in VS 2010
问题描述
我试图使用lambda传递代替函数指针,但VS2010似乎不能转换它。我已经尝试使用std ::功能像这样,它崩溃,我不知道如果我这样做正确!
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\\\
;
};
Concurrency :: CurrentScheduler :: ScheduleTask(f.target< void(void *)>(),0);
getch();
}
我似乎很奇怪,编译器不能将这样的lambda转换为一个简单的函数指针,因为它捕获没有变量 - 也在我不知道可以做什么的情况下。
每个lambda的类型是唯一的吗?所以我可以使用lambdas'类型作为模板参数来创建一个模板函数来生成一个唯一的静态函数,可以被调用而希望优化。
strong> UPDATED
以下似乎有效,但是安全吗?
#include< windows.h>
#include< conio.h>
#include< iostream>
#include< concrt.h>
模板< typename签名>
struct Bind
{
静态签名方法;
static void Call(void * parameter)
{
method(parameter);
}
};
模板< typename签名>
签名绑定< Signature> :: method;
模板< typename签名>
void ScheduleTask(签名方法)
{
Bind< Signature> :: method = method;
Concurrency :: CurrentScheduler :: ScheduleTask(& Bind< Signature> :: Call,0);
}
void main()
{
ScheduleTask
(
[](void *)
{
std :: cout<<Hello;
}
);
ScheduleTask
(
[](void *)
{
std :: cout< n;
}
);
getch();
}
已重新更新 b
所以有了帮助,我想出了更短的:
模板< typename签名>
void(* LambdaBind(Signature))(void *)
{
struct Detail
{
static void Bind(void * parameter)
{
签名方法;
method(parameter);
}
};
return& Detail :: Bind;
}
这可以用来包装没有 void(*)(void *)
到等效函数指针。看起来这在VS2010的更高版本中将变得不必要。
那么如何使用闭包来处理lambda?
适用于VS2010中的闭包 - 不知道它是否安全...
模板< typename签名>
struct Detail2
{
static std :: function< void(void *)>方法;
static void Bind(void * parameter)
{
method(parameter);
}
};
模板< typename签名>
std :: function< void(void *)> Detail2< Signature> :: method;
模板< typename签名>
void(* LambdaBind2(Signature method))(void *)
{
Detail2< Signature> :: method =
return& Detail2< Signature> :: Bind;
}
这个特性的lambda是在VS2010实施它们后添加的,所以它们不存在它。
这是一个可能的通用解决方法,未经测试:
#include< functional>
#include< iostream>
命名空间细节
{
//帮助专用化,
//定义转发方法
模板< typename Lambda,typename Func>
struct lambda_wrapper;
#define DEFINE_OPERATOR \
typedef decltype(& call)function_type; \
operator function_type(void)const \
{\
return& call; \
}
template< typename Lambda,typename C,typename R>
struct lambda_wrapper< Lambda,R(C :: *)(void)const>
{
static R call(void)
{
Lambda x;
return x();
}
DEFINE_OPERATOR
};
template< typename Lambda,typename C,typename R,
typename A0>
struct lambda_wrapper< Lambda,R(C :: *)(A0)const>
{
static R call(A0& p0)
{
Lambda x;
return x(std :: forward< A0>(p0));
}
DEFINE_OPERATOR
};
//等等
#undef DEFINE_OPERATOR
}
//封装一个lambda并提供
//一种调用方式it statically
template< typename Lambda>
struct lambda_wrapper:
detail :: lambda_wrapper< Lambda,decltype(& Lambda :: operator())>
{};
template< typename Lambda>
lambda_wrapper< Lambda> wrap_lambda(const Lambda&)
{
return lambda_wrapper Lambda();
}
int main(void)
{
auto l = [](){std :: cout< im broked :(<< std :: endl;};
std :: function< void(void)> f = wrap_lambda(l);
f
}
让我知道任何部分是否令人困惑。
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;
}
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:
#include <functional>
#include <iostream>
namespace detail
{
// helper specializations,
// define forwarding methods
template <typename Lambda, typename Func>
struct lambda_wrapper;
#define DEFINE_OPERATOR \
typedef decltype(&call) function_type; \
operator function_type(void) const \
{ \
return &call; \
}
template <typename Lambda, typename C, typename R>
struct lambda_wrapper<Lambda, R (C::*)(void) const>
{
static R call(void)
{
Lambda x;
return x();
}
DEFINE_OPERATOR
};
template <typename Lambda, typename C, typename R,
typename A0>
struct lambda_wrapper<Lambda, R (C::*)(A0) const>
{
static R call(A0&& p0)
{
Lambda x;
return x(std::forward<A0>(p0));
}
DEFINE_OPERATOR
};
// and so on
#undef DEFINE_OPERATOR
}
// wraps a lambda and provides
// a way to call it statically
template <typename Lambda>
struct lambda_wrapper :
detail::lambda_wrapper<Lambda, decltype(&Lambda::operator())>
{};
template <typename Lambda>
lambda_wrapper<Lambda> wrap_lambda(const Lambda&)
{
return lambda_wrapper<Lambda>();
}
int main(void)
{
auto l = [](){ std::cout << "im broked :(" << std::endl; };
std::function<void(void)> f = wrap_lambda(l);
f();
}
Let me know if any part is confusing.
这篇关于C ++ 0x Lambda到VS 2010中的函数指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!