std::get() 如何与 std::tuple 一起工作?

新手上路,请多包涵

在尝试自己制作 std::get<N>(std::tuple) 方法后,我不太确定编译器是如何实现的。我知道 std::tuple 有这样的构造函数:

 tuple(Args&&... args);

但是 args... 到底分配给了什么?我认为这对于了解 std::get() 的工作原理很有用,因为需要将参数放置在某个地方才能访问它们。

原文由 Me myself and I 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 818
1 个回答

这是 tuple 类的粗略玩具实现。

首先,一些元编程样板,用于表示整数序列:

 template<int...> struct seq {};
template<int max, int... s> struct make_seq:make_seq< max-1, max-1, s... > {};
template<int... s> struct make_seq<0, s...> {
  typedef seq<s...> type;
};
template<int max> using MakeSeq = typename make_seq<max>::type;

接下来,实际存储数据的标记类:

 template<int x, typename Arg>
struct foo_storage {
  Arg data;
};

每当我们想在编译时将数据与某个标记(在本例中为整数)相关联时,这种标记技术是一种常见的模式。标签(此处为 int )通常不在存储中的任何地方使用,它仅用于标记存储。

foo_helper 将一个序列和一组参数解压缩成一堆 foo_storage ,并以线性方式从它们继承。这是一种非常常见的模式——如果你经常这样做,你最终会创建为你做这件事的元编程工具:

 template<typename Seq, typename... Args>
struct foo_helper {};
template<int s0, int... s, typename A0, typename... Args>
struct foo_helper<seq<s0, s...>, A0, Args...>:
  foo_storage<s0, A0>,
  foo_helper<seq<s...>, Args...>
{};

我的粗略 tuple 类型, foo ,创建了一个包含一系列索引和参数的包,并将其传递给上面的助手。助手然后创建一堆包含父类的标记数据:

 template<typename... Args>
struct foo: foo_helper< MakeSeq<sizeof...(Args)>, Args... > {};

我从 foo 的主体中删除了所有内容,因为不需要实现 get

get is pretty simple: we take the storage type (not the tuple type), and the explicit template argument N disambiguates which of the foo_storage<n, T> 我们要去访问。现在我们有了存储类型,我们只需返回数据字段:

 template<int N, typename T>
T& get( foo_storage<N, T>& f )
 { return f.data; }
template<int N, typename T>
T const& get( foo_storage<N, T> const& f )
 { return f.data; }

我们正在使用 C++ 语言的重载机制来完成繁重的工作。当您使用类实例调用函数时,该实例作为每个父类都将检查是否可以使它们中的任何一个匹配。修复 N 后,只有一个父类是有效参数,因此会自动推导出父类(因此 T )。

最后,一些基本的测试代码:

 #include <iostream>

int main() {
  foo<int, double> f;
  get<0>( f ) = 7;
  get<1>( f ) = 3.14;
  std::cout << get<0>(f) << "," << get<1>(f) << "\n";
}

原文由 Yakk - Adam Nevraumont 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题