15

How can I get the arity of an arbitrary function type used as a template parameter?

The function can be a normal function, a lambda or a functor. Example:

template<typename TFunc>
std::size_t getArity() 
{
    // ...? 
}

template<typename TFunc>
void printArity(TFunc mFunc)
{
    std::cout << "arity: " << getArity<TFunc>() << std::endl;
}

void testFunc(int) { }

int main()
{
    printArity([](){}); // prints 0
    printArity([&](int x, float y){}); // prints 2
    printArity(testFunc); // prints 1
}

I have access to all C++14 features.

Do I have to create specialization for every function type (and all respective qualifiers)? Or is there an easier way?

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • 2
    What's your definition of arity of a variadic generic lambda? Or of a functor with multiple overloaded `operator ()`s taking different numbers of parameters? – T.C. Jan 09 '15 at 18:37
  • possible duplicate of [Is it possible to figure out the parameter type and return type of a lambda?](http://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda) – Barry Jan 09 '15 at 18:38
  • 1
    You only need two overloads: one for function pointers (easy, just use `sizeof...` on the deduced argument pack) and one for lambdas and other classes (take `decltype` of its `operator()` and then do the same thing). If `operator()` is overloaded, you're out of luck. – Brian Bi Jan 09 '15 at 18:41
  • 2
    @Brian Slightly more than two. 13 or 26, depending on whether you want to entertain C-style varargs functions. – T.C. Jan 09 '15 at 18:43
  • @T.C. I would simply omit C-style variadics (no well-defined answer) and pointers to member (can't be called the same way anyway). – Brian Bi Jan 09 '15 at 18:48
  • 2
    Have a look at: https://github.com/kennytm/utils/blob/master/traits.hpp –  Jan 09 '15 at 18:51
  • I suppose I did forget that `operator()`s can be cv-qualified too though. :( – Brian Bi Jan 09 '15 at 18:53

2 Answers2

20

Assuming that all the operator()'s and functions we're talking about are not templates or overloaded:

template <typename T>
struct get_arity : get_arity<decltype(&T::operator())> {};
template <typename R, typename... Args>
struct get_arity<R(*)(Args...)> : std::integral_constant<unsigned, sizeof...(Args)> {};
// Possibly add specialization for variadic functions
// Member functions:
template <typename R, typename C, typename... Args>
struct get_arity<R(C::*)(Args...)> :
    std::integral_constant<unsigned, sizeof...(Args)> {};
template <typename R, typename C, typename... Args>
struct get_arity<R(C::*)(Args...) const> :
    std::integral_constant<unsigned, sizeof...(Args)> {};

// Add all combinations of variadic/non-variadic, cv-qualifiers and ref-qualifiers

Demo.

Columbo
  • 60,038
  • 8
  • 155
  • 203
  • 2
    Is there a version like yours that also supports generic lambdas? http://coliru.stacked-crooked.com/a/1192b2686726d41d – Gam Sep 01 '17 at 00:12
-1

Years later but see my complete (free) solution here (production grade, fully documented). In your case you want helper template "ArgCount_v" (fully documented in above link). Applying it to your own code (displays the results you expected - see here):

#include <iostream>

// See https://github.com/HexadigmSystems/FunctionTraits
#include "TypeTraits.h" 

template<typename TFunc>
void printArity(TFunc mFunc)
{
    ////////////////////////////////////////////////
    // Everything in "TypeTraits.h" above declared
    // in this namespace
    ////////////////////////////////////////////////
    using namespace StdExt;

    /////////////////////////////////////////////////////  
    // Note: "tcout" (declared in "TypeTraits.h" above)
    // always resolves to "std::cout" on non-Microsoft
    // platforms and usually "std::wcout" on Microsoft
    // platforms (when compiling for UTF-16 in that
    // environment which is usually the case). You can
    // directly call "std::cout" or "std::wcout" instead
    // if you prefer, assuming you know which platform
    // you're always running on.
    /////////////////////////////////////////////////////  
    tcout << "arity: " << ArgCount_v<TFunc> << std::endl;
}

void testFunc(int) { }

int main()
{
    printArity([](){}); // prints 0
    printArity([&](int x, float y){}); // prints 2
    printArity(testFunc); // prints 1

    return 0;
}
Larry
  • 796
  • 6
  • 13