【问题标题】:Are there any reasons why c++ template packs are passed using std::tuple是否有任何理由使用 std::tuple 传递 c++ 模板包
【发布时间】:2016-05-31 15:56:15
【问题描述】:

假设我们要创建一个帮助类来反转模板包,例如如下:

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

我对@9​​87654324@(例如here)的经验表明它旨在存储数据,而不是在模板之间传递类型包。那么使用元组对可变参数进行操作有什么实际理由吗?

【问题讨论】:

  • 看一下这两个代码示例会发现长度减少了,因为不必重新创建 tuple_element
  • 函数参数类型可能不是数组,而元组元素类型可能是。
  • 函数签名是错误的选择。它调整其参数,例如将函数调整为函数指针,删除常量等。
  • 你还会用什么? structclassunion 不允许您检查里面有哪些类型和数量。有时你可以使用pair,但这确实是一个专门的tuple
  • 开发人员倾向于使用std::tuple,因为它带有开箱即用的tuple_element等功能。

标签: c++ templates tuples c++14 variadic-templates


【解决方案1】:

那么使用tuple 对可变参数进行操作有什么实际理由吗?

tuple 不对其参数执行任何转换 - tuple&lt;int[2]&gt; 确实包含 int[2] 作为其第一个类型,而 void(int[2]) 实际上是 void(int*)const、函数和其他经历衰减的类型也是如此。这使得功能成为一个不可行的选择。

如果您编写了自己的类型列表(例如template &lt;class... Ts&gt; struct typelist{};),您仍然需要重新实现std::getstd::tuple_elementstd::tuple_size。这就是tuple 的优点——它随时可用。

每个人都已经知道std::tuple 是什么。即使函数签名没有以会破坏的方式衰减它们的参数,我仍然会使用创建的类型作为类型的异构容器 - 而不是将您的解决方案硬塞到其他可以工作的东西中。最小意外原则。

【讨论】:

  • 缺点也很大:std::tuple 的重量相当大,创建几十或上百个实例确实会拖慢编译时间。
  • @Yakk 希望语言/库能够发展到 std::tuple 不是那么重量级的地步。
  • 是否可以将数组存储在带有tuple&lt;int[2]&gt; 的元组中?我认为你需要std::array&lt;&gt;。你能解释一下吗?
  • @JohannesSchaub-litb 是的,你可以。
  • 不过,tuple 仍然不能很好地处理某些类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-14
  • 2012-12-11
  • 2019-06-15
  • 2017-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多