Given a set of argument types and a function object, the return type can be deduced with decltype
. What about deducing argument types?
For a function pointer, both return and argument types can be deduced with a funny pattern matching syntax. As an example, here's a silly program that uses deduced argument types to print out a string describing the return and argument types of a function pointer.
#include <iostream>
#include <string>
using std::string;
template<class T>
string type_str();
template<>
string type_str<int>() { return "int"; }
template<>
string type_str<char>() { return "char"; }
string arg_types_str()
{
return "";
}
template<class T>
string arg_types_str()
{
return type_str<T>();
}
template<class T, class U, class... Args>
string arg_types_str()
{
return type_str<T>() + ", " + arg_types_str<U, Args...>();
}
template<class R, class... Args>
void print_fptr_type(R (*fptr)(Args...))
{
std::cout << type_str<R>() << " (*)(" << arg_types_str<Args...>() << ")" << std::endl;
}
int main()
{
int (*fptr)(char, int);
print_fptr_type(fptr);
}
Output:
int (*)(char, int)
Is it possible to write a program similar to the example that instead prints the return and argument types of function objects?
It seems like for a function object with exactly one operator()
, the argument types can in principle be deduced unambiguously.
Yes, it can be done. The strategy is similar but with a function object it's a two stage process. First, a member function pointer to operator()
is acquired and then a similar pattern matching method for type deduction can be used.
The key parts of the new program are:
template<class T, class R, class... Args>
void print_memfptr_types(R (T::*memfptr)(Args...))
{
std::cout << type_str<R>() << " (" << type_str<T>() << "*)(" << arg_types_str<Args...>() << ")" << std::endl;
}
template<class T, class R, class... Args>
void print_cmemfptr_types(R (T::*memfptr)(Args...))
{
std::cout << type_str<R>() << " (const " << type_str<T>() << "*)(" << arg_types_str<Args...>() << ")" << std::endl;
}
template<class T>
void print_fnc_obj_types(T&)
{
print_memfptr_types(&T::operator());
}
template<class T>
void print_fnc_obj_types(const T&)
{
print_cmemfptr_types(&T::operator());
}