16

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?

7
  • 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? Commented Jan 9, 2015 at 18:37
  • possible duplicate of Is it possible to figure out the parameter type and return type of a lambda? Commented Jan 9, 2015 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. Commented Jan 9, 2015 at 18:41
  • 2
    @Brian Slightly more than two. 13 or 26, depending on whether you want to entertain C-style varargs functions. Commented Jan 9, 2015 at 18:43
  • 2
    Have a look at: github.com/kennytm/utils/blob/master/traits.hpp Commented Jan 9, 2015 at 18:51

2 Answers 2

23

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Is there a version like yours that also supports generic lambdas? coliru.stacked-crooked.com/a/1192b2686726d41d
I won't claim to understand why, but I had better luck replacing the second declaration with template <typename R, typename... Args> struct get_arity<R(Args...)> : std::integral_constant<unsigned, sizeof...(Args)> {};. With <R(*)(Args...)> I was unable to get the arity of a function passed by const reference.
@Tom7 There is no such thing as a const-qualified reference to a function. Can you show an example?
@Columbo Like this: template<typename F> void Apply(const F &f) { f(0); } See godbolt.org/z/Y3Wqooq5K
@Tom7 Yep, you can just add a partial specialization for function (non-pointer) type, as you showed. References to functions or pure function types are not handled :-)
0

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;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.