How to get all types of parameters from a parameter package?

I have the following code snippet where I define a struct quick with a static template using the random method with some specializations:

(I used function_traits from another SO answer. Attached below for reference.)

 struct quick { template <typename T> static T random(); template <typename F> static void check(F f) { constexpr auto arity = function_traits<F>::arity; // easy :) std::cout << arity << std::endl; typedef typename function_traits<F>::template arg<0>::type type0; // easy:) // how to get all types of all F parameters? } }; template <> std::string quick::random<std::string>() { return std::string("test"); } template <> int quick::random<int>() { return 1; } 

I would like to get all types of F parameters inside check so that I can generate a tuple with random entries (based on my random methods).

Same:

 auto t0 = std::make_tuple(quick::random<AllTypes>()...); //pseudo code auto t = std::make_tuple(quick::random < function_traits<F>::template arg<std::make_index_sequence<arity>>::type... > ()... ); 

I tried with something like:

 template<typename F, typename ...TIdxs> using ArgTypes = typename function_traits<F>::template arg<TIdxs>::type...; // ... // inside check typedef ArgTypes<F, std::make_index_sequence<arity>> types; 

but failed:

 main.cpp:80:72: error: expected ';' before '...' token using ArgTypes = typename function_traits<F>::template arg<TIdxs>::type...; ^ main.cpp: In static member function 'static void quick::check(F, D)': main.cpp:98:15: error: 'ArgTypes' does not name a type typedef ArgTypes<F, std::make_index_sequence<arity>> types; 

I used the function traits utilities from this SO answer.

 template <typename T> struct function_traits : function_traits<decltype(&T::operator())> {}; // For generic types, directly use the result of the signature of its 'operator()' template <typename ClassType, typename ReturnType, typename... Args> struct function_traits<ReturnType(ClassType::*)(Args...) const> // we specialize for pointers to member function { enum { arity = sizeof...(Args) }; // arity is the number of arguments. typedef ReturnType result_type; template <size_t i> struct arg { typedef typename std::tuple_element<i, std::tuple<Args...>>::type type; // the i-th argument is equivalent to the i-th tuple element of a tuple // composed of those arguments. }; }; 
+5
source share
3 answers

Note that in function_traits you already have all types of arguments. All you have to do is expose them:

 template <typename ClassType, typename ReturnType, typename... Args> struct function_traits<ReturnType(ClassType::*)(Args...) const> // we specialize for pointers to member function { enum { arity = sizeof...(Args) }; using result_type = ReturnType; using all_args = std::tuple<Args...>; // <-- add this template <size_t i> // <-- consider making this an alias template using arg = std::tuple_element_t<i, all_args>; }; 

And now getting all the arguments to the function is just function_traits<F>::all_args .


If you do not want to change function_traits , we just need to add an external metafung:

 template <class F, class = std::make_index_sequence<function_traits<F>::arity>> struct all_args; template <class F, size_t... Is> struct all_args<F, std::index_sequence<Is...>> { using type = std::tuple<typename function_traits<F>::template arg<Is>::type...>; }; template <class F> using all_args_t = typename all_args<F>::type; 
+3
source
 template<class=void,std::size_t...Is> auto tupler(std::index_sequence<Is...>){ return [](auto&&f){ return std::make_tuple( f(std::integral_constant<std::size_t,Is>{})... ); } } template<std::size_t N> auto tupler(){ return tupler(std::make_index_sequence<N>{}); } 

This allows you to expand parameter packages inside a string and create a tuple.

Just

 auto t = tupler<ArgCount>()([&](auto i){ return random<typename func_trait::arg<i>::type>(); }); 

Where func_trait is an alias for the above thing.

Alternatively, replace struct arg with the using alias. Cleaner.

+2
source

Not sure if this is what you want, but ... how about changing quick as follows?

 struct quick { template <typename T> static T random(); template<typename F, std::size_t I> using ArgTypes = typename function_traits<F>::template arg<I>::type; template<typename F, std::size_t ... Is> using ArgTuple = std::tuple< ArgTypes<F, Is>... >; template <typename F, std::size_t ... Is> static ArgTuple<F, Is...> makeArgTuple () { return make_tuple(quick::random<Is>()...); } template <typename F> static void check(F f) { constexpr auto arity = function_traits<F>::arity; // easy :) std::cout << arity << std::endl; typedef typename function_traits<F>::template arg<0>::type type0; // easy:) auto t = ArgTuple<F, std::make_index_sequence<arity>::type> (); auto t2 = makeArgTuple<F, std::make_index_sequence<arity>::type>(); } }; 

You made a mistake by skipping typename TIdxs to arg ; arg requires std::size_t .

Note that std::make_index_sequence is a C ++ 14 function (but it is easy to create in C ++ 11 as well).

ps: Sorry for my bad english.

-1
source

All Articles