我正在尝试实现一种机制,它会为我提供一些有关模板参数函数类型的信息。 主要思想是获取参数的数量、返回类型、每个参数的大小总和。 我有一些基于 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, "!");
}
或者更简单,只有一个特征类:
#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, "!");
}
注意:不幸的是,以上解决方案均不适用于通用 lambda,相关讨论是 Arity of a generic lambda
关于用于获取函数参数数量的 C++ 模板机制,适用于 lambda 和普通函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27024238/