As a general answer to your question (how to do tuple unpacking), parameter packs can only be generated implicitly in the context of template argument type deduction, so if you want to "unpack" a type tuple<T1, ..., Tn>
into a sequence of types T1, ..., Tn
you have to instantiate that tuple and supply that instance in input to some function template:
template<typename... Ts>
void unpack(tuple<Ts...> const&) // Now you have an argument pack...
However, considering what you want to achieve (get a WinAPI callback from a lambda), I would not rely on tuples, and rather use a free function template. That can be done without introducing many levels of indirections and wrappers. Here is a possible simple solution:
#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...);
}
}
This is the framework. And this is how you would use it:
#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;
}
If you don't mind macros and want to simplify that further for some usage patterns (like the one above), you can add a macro like this:
#define get_api_callback(lambda) \
&lambda_caller<decltype(lambda)>; singleton<decltype(lambda)>::set_instance(lambda);
That would change your main()
function into the following:
#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;
}