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.
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)>{});
}
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.