How to extract lambda's Return Type and Variadic Parameters Pack back from general template<typename T>

纵饮孤独 提交于 2019-12-04 10:07:52
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>
// we specialize for pointers to member function
{
    using result_type = ReturnType;
    using arg_tuple = std::tuple<Args...>;
    static constexpr auto arity = sizeof...(Args);
};

template <class F, std::size_t ... Is, class T>
auto lambda_to_func_impl(F f, std::index_sequence<Is...>, T) {
    return std::function<typename T::result_type(std::tuple_element_t<Is, typename T::arg_tuple>...)>(f);
}

template <class F>
auto lambda_to_func(F f) {
    using traits = function_traits<F>;
    return lambda_to_func_impl(f, std::make_index_sequence<traits::arity>{}, traits{});
}

The code above should do what you want. The main idea, as you can see, is to create an integer pack. This is the non-type template equivalent of variadics. I don't know of any technique by which you can use such a pack without calling another function, so typically in these situations with tuples you'll see a nested "impl" function that does all the work. Once you have the integer pack, you expand it while accessing the tuple (works for getting the values too).

On a stylistic note: use using, not typename, especially in template heavy code as the former can alias templates too. And don't use that enum trick to store a static value without it using space; compilers will optimize this out anyhow and just using a static constexpr integer is much clearer.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!