Is there a standard way to get the types of a function's arguments and pass around these types as a template parameter pack? I know that this is possible in C++ because it has been done before.
I was hoping that with C++14 or the upcoming C++1z, there would be an idiomatic way to implement arg_types<F>...
here:
template <typename ...Params> void some_function(); // Params = const char* and const char* FILE* fopen(const char* restrict filename, const char* restrict mode); int main(){ some_function<arg_types<fopen>...>(); }
Just to be clear, an answer claiming that there is no standard way to do this is not an answer. If there is no answer, I would prefer that the question remain unanswered until the solution is added to C++500 or until the heat death of the universe, whichever happens earlier :)
Edit: A deleted answer noted that I can use PRETTY_FUNCTION
to get the names of parameter types. However, I want the actual types. Not the names of those types.
Parameters in C functions There are two ways to pass parameters in C: Pass by Value, Pass by Reference.
The parameter in C refers to any declaration of variables within the parenthesis during the function declaration. These are listed in the function's definition, separated by commas. Example of Parameter. int add (int a, int b) { int c = a + b; return c; } In the above lines of code, we can see the function definition.
Parameter Types Presently, the type is one of ref, const, or val. The type indicates the relationship between the actual argument and the formal parameter. , for a full discussion of references.)
This syntax is slightly different.
First, because types are easier to work with than packs, a type that holds a pack. The using type=types;
just saves me work in the code that generates a types
:
template<class...>struct types{using type=types;};
Here is the workhorse. It takes a signature, and produces a types<?...>
bundle containing the arguments for the signature. 3 steps so we can get nice clean C++14esque syntax:
template<class Sig> struct args; template<class R, class...Args> struct args<R(Args...)>:types<Args...>{}; template<class Sig> using args_t=typename args<Sig>::type;
Here is a syntax difference. Instead of directly taking Params...
, we take a types<Params...>
. This is similar to the "tag dispatching" pattern, where we exploit template function type deduction to move arguments into the type list:
template <class...Params> void some_function(types<Params...>) { }
My fopen
is different, because I don't want to bother #include
ing stuff:
void* fopen(const char* filename, const char* mode);
And the syntax is not based off of fopen
, but rather the type of fopen
. If you have a pointer, you'd need to do decltype(*func_ptr)
or somesuch. Or we could augment the top to handle R(*)(Args...)
for ease of use:
int main(){ some_function(args_t<decltype(fopen)>{}); }
live example.
Note that this does not work with overloaded functions, nor does it work with function objects.
In general, this kind of thing is a bad idea, because usually you know how you are interacting with an object.
The above would only be useful if you wanted to take a function (or function pointer) and pop some arguments off some stack somewhere and call it based off the parameters it expected, or something similar.
Use Boost.FunctionTypes and std::index_sequence
. Below is an example which prints the argument types of the function func
. You can change the doit
static function to do what you want. See it in action here.
template <typename FuncType> using Arity = boost::function_types::function_arity<FuncType>; template <typename FuncType> using ResultType = typename boost::function_types::result_type<FuncType>::type; template <typename FuncType, size_t ArgIndex> using ArgType = typename boost::mpl::at_c<boost::function_types::parameter_types<FuncType>, ArgIndex>::type; void func(int, char, double) {} template <typename Func, typename IndexSeq> struct ArgPrintHelper; template <typename Func, size_t... Inds> struct ArgPrintHelper<Func, integer_sequence<size_t, Inds...> > { static void doit() { string typeNames[] = {typeid(ResultType<Arg>).name(), typeid(ArgType<Func, Inds>).name()...}; for (auto const& name : typeNames) cout << name << " "; cout << endl; } }; template <typename Func> void ArgPrinter(Func f) { ArgPrintHelper<Func, make_index_sequence<Arity<Func>::value> >::doit(); } int main() { ArgPrinter(func); return 0; }
Headers(moved down here to reduce noise in the above code snippet):
#include <boost/function_types/function_type.hpp> #include <boost/function_types/parameter_types.hpp> #include <boost/function_types/result_type.hpp> #include <boost/function_types/function_arity.hpp> #include <algorithm> #include <iostream> #include <string> #include <type_traits> #include <typeinfo> #include <tuple> #include <utility> using namespace std;
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