Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get types of C++ function parameters

Tags:

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.

like image 799
Navin Avatar asked Feb 13 '15 21:02

Navin


People also ask

What are the types of parameters used in C functions?

Parameters in C functions There are two ways to pass parameters in C: Pass by Value, Pass by Reference.

What are parameters in function in C?

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.

What are the 2 types of function parameters?

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.)


2 Answers

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 #includeing 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.

like image 172
Yakk - Adam Nevraumont Avatar answered Oct 09 '22 03:10

Yakk - Adam Nevraumont


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; 
like image 35
Pradhan Avatar answered Oct 09 '22 05:10

Pradhan