but what I really want to know is how to make available the content of the Args inside the function_traits to access it from outside, and how to "inline" multiple templates and then expand them.
First of all, the simplest solution that come in my mind to solve you particular problem with l2f()
is define a specific type as the signature
suggested by PasserBy.
I propose a slightly different solution but the idea is the same: you can define
using func_type = std::function<ReturnType(Args...)>;
so l2f()
simply become
template <typename Func>
constexpr auto l2f (Func lambda)
{ return static_cast<typename function_traits<Func>::func_type>(lambda); }
For the more general problem (" how to make available the content of the Args inside the function_traits to access it from outside, and how to "inline" multiple templates and then expand them") I suggest to avoid to define the template arg
struct but simply define a tuple type inside function_traits
using tuple_type = std::tuple<Args...>;
Next you have to call an helper function to transform the arity
inside the function_traits
in a std::index_sequence
template <typename Func>
constexpr auto l2f (Func lambda)
{ return l2f_helper(lambda,
std::make_index_sequence<function_traits<Func>::arity>{}); }
and the helper function can be written as
template <typename Func, std::size_t ... Is>
constexpr auto l2f_helper (Func lambda,
std::index_sequence<Is...> const &)
{
return static_cast<std::function<
typename function_traits<Func>::result_type(
std::tuple_element_t<Is,
typename function_traits<Func>::tuple_type> ...)>>(lambda);
}
Ugly. I know.
The following is a full compilable example with both versions of l2f
and a modified function_traits
.
#include <tuple>
#include <iostream>
#include <functional>
#include <type_traits>
template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{ };
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
static constexpr std::size_t arity { sizeof...(Args) };
using result_type = ReturnType;
using func_type = std::function<ReturnType(Args...)>;
using tuple_type = std::tuple<Args...>;
};
template <typename Func>
constexpr auto l2f_v1 (Func lambda)
{ return static_cast<typename function_traits<Func>::func_type>(lambda); }
template <typename Func, std::size_t ... Is>
constexpr auto l2f_v2_helper (Func lambda,
std::index_sequence<Is...> const &)
{
return static_cast<std::function<
typename function_traits<Func>::result_type(
std::tuple_element_t<Is,
typename function_traits<Func>::tuple_type> ...)>>(lambda);
}
template <typename Func>
constexpr auto l2f_v2 (Func lambda)
{ return l2f_v2_helper(lambda,
std::make_index_sequence<function_traits<Func>::arity>{}); }
int main ()
{
auto f1 = l2f_v1([](int, long){ std::cout << "lambda1!" << std::endl; });
auto f2 = l2f_v2([](int, long){ std::cout << "lambda2!" << std::endl; });
f1(1, 2L);
f2(2, 3L);
static_assert( std::is_same<decltype(f1), decltype(f2)>{}, "!" );
}
A little improvement: if you also define the following using
template inside function_traits
template <std::size_t I>
using a_type = std::tuple_element_t<I, tuple_type>;
the helper function can be simplified as follows
template <typename Func, std::size_t ... Is>
constexpr auto l2f_helper (Func lambda,
std::index_sequence<Is...> const &)
{
return static_cast<std::function<
typename function_traits<Func>::result_type(
typename function_traits<Func>::template a_type<Is>...)>>(lambda);
}