C ++ for getting the number of function arguments that will work for lambda and normal functions

I am trying to implement a mechanism that will provide me with some information about the function type of a template argument. The basic idea is to get the number of arguments, the return type, the total sum of the sizes of each argument. I have something for a lambda based on this entry .

template <typename T, typename... Args>
struct sumSizeOfArgs {
    enum { totalSize = sizeof(typename std::decay<T>::type) + sumSizeOfArgs<Args...>::totalSize };
};

template<typename T>
struct sumSizeOfArgs<T> {
    enum  {totalSize = sizeof(typename std::decay<T>::type)};
};
}             
template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};

template <typename ClassType, typename ReturnType, typename... Args>

struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
  enum { arity = sizeof...(Args) };

  typedef ReturnType result_type;

enum { totalSize = sumSizeOfArgs<Args...>::totalSize };

template <size_t i>
struct arg
{
    typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
};
};

      

However, indeed, this code does not work for normal function types such as

 function_traits<void()>

      

it has no operator (). I would really appreciate any suggestion to make this code for both cases. Thank,

+3


source to share


1 answer


Slightly improved original detail:

#include <tuple>
#include <type_traits>

template <typename... Args>
struct sumSizeOfArgs
{
    static constexpr size_t totalSize = 0;
};

template <typename T, typename... Args>
struct sumSizeOfArgs<T, Args...>
{
    static constexpr size_t totalSize = sizeof(typename std::decay<T>::type)
                                        + sumSizeOfArgs<Args...>::totalSize;
};

template <typename T>
struct sumSizeOfArgs<T>
{
    static constexpr size_t totalSize = sizeof(typename std::decay<T>::type);
};

template <typename T>
struct function_traits_impl;

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(ClassType::*)(Args...)>
{
    static constexpr size_t arity = sizeof...(Args);

    using result_type = ReturnType;

    static constexpr size_t totalSize = sumSizeOfArgs<Args...>::totalSize;

    template <size_t i>
    struct arg
    {
        using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
    };
};

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(ClassType::*)(Args...) const>
    : function_traits_impl<ReturnType(ClassType::*)(Args...)> {};

      

This is where the new part begins (partial specialization of feature classes for functions):

template <typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(Args...)>
{
    static constexpr size_t arity = sizeof...(Args);

    using result_type = ReturnType;

    static constexpr size_t totalSize = sumSizeOfArgs<Args...>::totalSize;

    template <size_t i>
    struct arg
    {
        using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
    };
};

template <typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(*)(Args...)>
    : function_traits_impl<ReturnType(Args...)> {};

      

An important role here (determination of availability operator()

):

template <typename T, typename V = void>
struct function_traits
    : function_traits_impl<T> {};

template <typename T>
struct function_traits<T, decltype((void)&T::operator())>
    : function_traits_impl<decltype(&T::operator())> {};

      

Test:

int main()
{
    static_assert(function_traits<void()>::arity == 0, "!");

    static_assert(function_traits<void(int)>::arity == 1, "!");

    static_assert(function_traits<void(*)(int, float)>::arity == 2, "!");  

    auto lambda = [] (int, float, char) {};
    static_assert(function_traits<decltype(lambda)>::arity == 3, "!");

    auto mutable_lambda = [] (int, float, char, double) mutable {};
    static_assert(function_traits<decltype(mutable_lambda)>::arity == 4, "!");
}

      



DEMO 1


Or even simpler, with one class of traits:

#include <tuple>

template <typename ReturnType, typename... Args>
struct function_traits_defs
{
    static constexpr size_t arity = sizeof...(Args);

    using result_type = ReturnType;

    template <size_t i>
    struct arg
    {
        using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
    };
};

template <typename T>
struct function_traits_impl;

template <typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(Args...)>
    : function_traits_defs<ReturnType, Args...> {};

template <typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(*)(Args...)>
    : function_traits_defs<ReturnType, Args...> {};

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(ClassType::*)(Args...)>
    : function_traits_defs<ReturnType, Args...> {};

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits_impl<ReturnType(ClassType::*)(Args...) const>
    : function_traits_defs<ReturnType, Args...> {};

// + other cv-ref-variations

template <typename T, typename V = void>
struct function_traits
    : function_traits_impl<T> {};

template <typename T>
struct function_traits<T, decltype((void)&T::operator())>
    : function_traits_impl<decltype(&T::operator())> {};

int main()
{
    static_assert(function_traits<void()>::arity == 0, "!");

    static_assert(function_traits<void(int)>::arity == 1, "!");

    static_assert(function_traits<void(*)(int, float)>::arity == 2, "!");  

    auto lambda = [] (int, float, char) {};
    static_assert(function_traits<decltype(lambda)>::arity == 3, "!");

    auto mutable_lambda = [] (int, float, char, double) mutable {};
    static_assert(function_traits<decltype(mutable_lambda)>::arity == 4, "!");

    struct Functor
    {
        void operator()(int) {}
    };
    static_assert(function_traits<Functor>::arity == 1, "!");
}

      

DEMO 2


Note: Unfortunately none of the above solutions will work for generic lambdas, the related discussion on Arity of generic lambda

+4


source







All Articles