我们想说我们要创建一个帮助类来反转模板包,例如如下:
#include <tuple>
#include <utility>
#include <typeinfo>
#include <iostream>
template <class>
struct sizer;
template <template<class...> class Pack, class... Args>
struct sizer<Pack<Args...>> {
static constexpr size_t value = sizeof...(Args);
};
template <class Pack, class Indices = std::make_index_sequence<sizer<Pack>::value>>
struct reverse_pack;
template <class... Args, size_t... I>
struct reverse_pack<std::tuple<Args...>, std::integer_sequence<std::size_t, I...>> {
using type = typename std::tuple<typename std::tuple_element<(sizeof...(Args) - I - 1), std::tuple<Args...>>::type...>;
};
int main() {
std::cout << typeid(reverse_pack<std::tuple<int, float, double>>::type).name() << std::endl;
}
我们可以使用例如成功完成同样的事情。函数签名作为模板参数:
#include <utility>
#include <typeinfo>
#include <iostream>
template <class>
struct sizer;
template <class... Args>
struct sizer<void(Args...)> {
static constexpr size_t value = sizeof...(Args);
};
template <size_t N, class Sign>
struct nth_param;
template <size_t N, class First, class... Args>
struct nth_param<N, void(First, Args...)>: nth_param<N-1, void(Args...)> { };
template <class First, class... Args>
struct nth_param<0, void(First, Args...)> {
using type = First;
};
template <class Pack, class Indices = std::make_index_sequence<sizer<Pack>::value>>
struct reverse_pack;
template <class... Args, size_t... I>
struct reverse_pack<void(Args...), std::integer_sequence<std::size_t, I...>> {
using type = void(typename nth_param<(sizeof...(Args) - I - 1), void(Args...)>::type...);
};
int main() {
std::cout << typeid(reverse_pack<void(int, float, double)>::type).name() << std::endl;
}
我对std::tuple
的体验(例如here)显示其旨在存储数据,而不是在模板之间传递类型包。那么使用元组来操作可变参数有什么实际的理由吗?
答案 0 :(得分:7)
那么使用
tuple
来操作可变参数有什么实际的理由吗?
tuple
没有对其参数执行任何转换 - tuple<int[2]>
确实包含int[2]
作为其第一种类型,而void(int[2])
实际上是void(int*)
。同样适用于const
,函数和其他经历衰变的类型。这使得功能成为一种不可行的选择。
如果您编写了自己的类型列表(例如template <class... Ts> struct typelist{};
),则仍需要重新实现std::get
,std::tuple_element
和std::tuple_size
。这是关于tuple
的好处 - 它准备就绪并且很有用。
每个人都已经知道std::tuple
是什么。即使函数签名没有以一种破坏的方式来破坏它们的论点,我仍然会使用所创建的类型作为异类的类型容器 - 而不是将你的解决方案变成其他碰巧的解决方案工作。最不惊讶的原则和所有。