我需要传递一个Lambda作为回调(特别是WinAPI)。思路如下:
-
将lambda存储在单例类中(每个lambda,也是两个相同的lambda,具有不同的类型),因此它应该是安全的
LambdaSingleton<Lambda_Type>::instance = l;
-
传递调用lambda实例的静态方法的地址作为回调。
template < typename Lambda, typename Callback_Signature_R, typename... Callback_Signature_Args> struct LambdaCallbackSupport{ /** * Callback method * * @param args * The parameters to feed to the lambda * @return * The return value of the execution of the lambda */ static Callback_Signature_R __stdcall callback(Callback_Signature_Args... args){ return LambdaSingleton<Lambda>::instance(args); } };
我已经有了一个工作类,用于在编译时提取有关函数的信息:
template<
typename C,
typename R,
typename... Args>
struct Traits<R(__stdcall *)(Args...) const>{
//various typedefs for R, tuple of args, arity etc..
};
那么我将得到这样的内容:
//Example lambda
int toBeCaptured = 8;
auto lambda =
[&](std::string& str) -> size_t{
return toBeCaptured + str.length();
};
typedef decltype(lambda) Lambda;
//Expected callback signature
typedef size_t(__stdcall *CallbackSignature)(std::string&);
//Configure a callback support and pass its method
typedef Traits<CallbackSignature> callbackTraits;
typedef LambdaCallbackSupport<
Lambda,
callbackTraits::Result_Type,
callbackTraits::Args_Tuple_Pack> CallbackSupportType;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //How to unpack the tuple without actually have the arguments??
//Store the lambda instance statically
Singleton<Lambda>::instance = lambda;
//Pass the callback
void* pFunc = &CallbackSupportType::callback;
//Simulate invocation of callback
std::string str("may work?");
size_t ret = (*pFunc)(str);
因为我只需要让编译器生成一个回调类专门化(而不是实际调用它的方法)我如何应用迭代解包技术在这个网站上的其他问题中提出的?
谢谢
作为你的问题(如何做元组解包)的一般答案,参数包只能在模板参数类型演绎的上下文中隐式地生成,所以如果你想将类型tuple<T1, ..., Tn>
"解包"为类型T1, ..., Tn
序列,你必须实例化该元组并将该实例提供给一些函数模板:
template<typename... Ts>
void unpack(tuple<Ts...> const&) // Now you have an argument pack...
然而,考虑到你想要实现什么(从lambda获得WinAPI回调),我不会依赖于元组,而是使用一个自由的函数模板。这可以在不引入许多层次的间接和包装器的情况下完成。下面是一个可能的简单解决方案:
#include <type_traits>
#include <memory>
template<typename F>
struct singleton
{
static void set_instance(F f) { instance.reset(new F(f)); }
static std::unique_ptr<F> instance;
};
template<typename F>
std::unique_ptr<F> singleton<F>::instance;
template<typename F, typename... Ts>
typename std::result_of<F(Ts...)>::type __stdcall lambda_caller(Ts... args)
{
if (singleton<F>::instance == nullptr)
{
// throw some exception...
}
else
{
return (*(singleton<F>::instance))(args...);
}
}
这是框架。你可以这样使用它:
#include <iostream>
int main()
{
//Example lambda
int toBeCaptured = 8;
auto lambda =
[&](std::string& str) -> size_t{
return toBeCaptured + str.length();
};
singleton<decltype(lambda)>::set_instance(lambda);
size_t (__stdcall *pfn)(std::string&) = &lambda_caller<decltype(lambda)>;
std::string str = "hello";
int out = pfn(str);
std::cout << out;
return 0;
}
如果你不介意宏,并希望进一步简化一些使用模式(如上面的),你可以添加一个宏:
#define get_api_callback(lambda)
&lambda_caller<decltype(lambda)>; singleton<decltype(lambda)>::set_instance(lambda);
这将改变您的main()
函数如下:
#include <iostream>
int main()
{
//Example lambda
int toBeCaptured = 8;
auto lambda =
[&](std::string& str) -> size_t{
return toBeCaptured + str.length();
};
// As simple as that...
size_t (__stdcall *pfn)(std::string&) = get_api_callback(lambda);
std::string str = "hello";
int out = pfn(str);
std::cout << out;
return 0;
}