用于获取函数参数数量的 C++ 模板机制,适用于 lambda 和普通函数

标签 c++ templates c++11 lambda

我正在尝试实现一种机制,它会为我提供一些有关模板参数函数类型的信息。 主要思想是获取参数的数量、返回类型、每个参数的大小总和。 我有一些基于 this entry 的 lambda 运行.

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

但是,实际上此代码不适用于普通函数类型,例如

 function_traits<void()>

它没有 operator()。如果有任何使此代码适用于这两种情况的建议,我将不胜感激。 谢谢,

最佳答案

略微改进了原始部分:

#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...)> {};

新部分从这里开始(特征的类函数偏特化):

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...)> {};

关键部分在这里(确定 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())> {};

测试:

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


或者更简单,只有一个特征类:

#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


注意:不幸的是,以上解决方案均不适用于通用 lambda,相关讨论是 Arity of a generic lambda

关于用于获取函数参数数量的 C++ 模板机制,适用于 lambda 和普通函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27024238/

相关文章:

c++ - 检索 libevent 连接信息时“转发结构声明”

c++ - C++/Qt 编写的程序中的 RTF/doc/docx 文本提取

c++ - 多个线程访问共享资源

c++ - 编写基于模板的工厂系统

c++ - 以多模板类中的模板为条件

c++ - visual studio 中智能指针对象的自定义 View ?

c++ - Reserve() - 空 vector 上的 data() 技巧 - 这是正确的吗?

c++ - 提供方法指针和派生类型对象时 std::bind 的一致性

c++ - std::list<char> 列表类型为 (char * data, int length)

c++ - 向标准模板的特化添加新方法(std::vector、std::list...)