Let's suppose I have a template function which takes an argument, which is a function (it can be a std::function, or a lambda, or actual function pointer). A silly example that illustrates the problem:
template<typename F,typename A,typename B = typename std::result_of<F(A)>::type>
B blabla(F &&f)
{
return f(A())/3;
}
I can reference the return type of f with std::result_of::typename, given I have the type of A, but I would like the compiler to deduce type A from F's first argument. (If I write
template<typename A,typename B>
B blabla(const std::function<B(A)> &f)
{
return f(A())/3;
}
the compiler have problems deducing A and B (especially if it's not an std::function but a lambda), so this is not the right way to do it.)
This won't work for generic lambdas or arbitrary functors whose operator()
is overloaded or is a template.
// primary template.
template<class T>
struct function_traits : function_traits<decltype(&T::operator())> {
};
// partial specialization for function type
template<class R, class... Args>
struct function_traits<R(Args...)> {
using result_type = R;
using argument_types = std::tuple<Args...>;
};
// partial specialization for function pointer
template<class R, class... Args>
struct function_traits<R (*)(Args...)> {
using result_type = R;
using argument_types = std::tuple<Args...>;
};
// partial specialization for std::function
template<class R, class... Args>
struct function_traits<std::function<R(Args...)>> {
using result_type = R;
using argument_types = std::tuple<Args...>;
};
// partial specialization for pointer-to-member-function (i.e., operator()'s)
template<class T, class R, class... Args>
struct function_traits<R (T::*)(Args...)> {
using result_type = R;
using argument_types = std::tuple<Args...>;
};
template<class T, class R, class... Args>
struct function_traits<R (T::*)(Args...) const> {
using result_type = R;
using argument_types = std::tuple<Args...>;
};
// additional cv-qualifier and ref-qualifier combinations omitted
// sprinkle with C-style variadics if desired
Then
template<class T>
using first_argument_type = typename std::tuple_element<0, typename function_traits<T>::argument_types>::type;
Replace 0 with the desired number as needed, or write a separate alias that also take an index. Demo.
#include <boost/type_traits.hpp>
boost::function_traits<decltype(function)>::arg2_type
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With