Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get number of function arguments from `decltype(<funtion>)`?

Let's say I have the following function declaration:

template<typename signature>
int foo();

Given the above-mentioned function, is it possible to define foo in such a way, so that it returns the number of function arguments that were passed in the decltype template parameter?

So the example usage might look like:

int bar(int a, int b) 
{
    return a + b;
}

int jar(int a)
{
    return a * a;
}

int main() 
{
    std::cout << foo<decltype(bar)>() << std::endl; // Desired output: 2
    std::cout << foo<decltype(jar)>() << std::endl; // Desired output: 1
}

Edit:

Thanks, everyone for the replies. They do seem to work. However, I forgot to mention one more use case.

Let's say I want to get the number of arguments of the following function:

int __stdcall car(int a, int b, int c)
{
    return a * b + c;
}

The answers so far do not seem to work with this kind of function that uses __stdcall convention.

Any idea why and what can be done about it?

like image 946
arslancharyev31 Avatar asked Jul 10 '20 04:07

arslancharyev31


2 Answers

For that(i.e. with decltype), the given foo is not enough. You need something like the followings traits.

template<typename> struct funtion_args final {};

template<typename ReType, typename... Args>
struct funtion_args<ReType(Args...)> final
{
   static constexpr std::size_t noArgs = sizeof...(Args);
};

Used sizeof... operator on the variadic template arguments, to get the no of arguments. And then you can get the argument count directly like

std::cout << funtion_args<decltype(bar)>::noArgs << "\n"; // output: 2

or pack into the foo

template<typename signature>
constexpr std::size_t foo() noexcept
{
   return funtion_args<signature>::noArgs;
}

(See Live Demo)


Better Approach

If you want less typing(i.e. without decltype), a more convenient way of getting the arguments count of a free-function, you could do the following

template <typename ReType, typename... Args> 
constexpr auto foo(ReType(*)(Args...)) noexcept
{
   return sizeof...(Args);
}

Now you could conveniently call the foo with other functions as arguments

std::cout << foo(bar) << "\n"; // output: 2

(See Live Demo)

like image 84
JeJo Avatar answered Nov 15 '22 09:11

JeJo


Sure, just have foo() call on a suitable trait type. For example:

template <typename T>
struct foo_helper;

template <typename T, typename... Args>
struct foo_helper<T(Args...)> {
    static constexpr std::size_t arg_count = sizeof...(Args);
};

template <typename T>
std::size_t foo() {
    return foo_helper<T>::arg_count;
}
like image 42
cdhowie Avatar answered Nov 15 '22 09:11

cdhowie