【问题标题】:Why STL algorithms are not overloaded for std::tuple?为什么 STL 算法不会为 std::tuple 重载?
【发布时间】:2018-05-23 08:31:10
【问题描述】:

我想知道为什么某些 STL 算法没有重载以使它们可用于元组。有些人是指那些不重新排序元素的人。一个很好的例子可能是std::for_each

是否存在语言限制,例如不可能混合编译时评估和运行时评估?让我澄清一下最后一句话:

我知道迭代本身需要成为编译时迭代,然后必须定义编译时迭代器才能使用编译时 std::get<> 来获取值。之后,应该可以将模板化的 lambda 应用于元组中的每个异生类型,但该类型的值随后会在运行时评估。

我认为这应该是可能的,即使我个人不知道从哪里开始。我看到了看起来不像std::for_each 的实现来达到相同的结果。为什么会这样?

(注意:“元组”是指std::pairstd::tuple

【问题讨论】:

  • 考虑到std::pairstd::tuple 都允许您存储完全不同的(异构)类型,这会有点困难。当存储的类型没有共同点时,您将如何应用任何标准库算法?
  • 元组和对是不同数据类型的混合。当每个元素都是不同的类型时,您将如何编写通用函数?
  • 难道不能用模板化的 lambda 传递一个适用于任何数据类型的函数吗?例如:[](const auto& value){ std::cout << value; }
  • auto 不是“与我匹配任何类型”。 auto 是编译器在编译时推导出的类型。它只是一种类型。
  • 难道不应该将其扩展到许多不同的仿函数类型吗?

标签: c++ tuples std-pair stl-algorithm stdtuple


【解决方案1】:

STL算法使用迭代器,与std::tuple不兼容。

std::tuple 有自己的一组函数,所以你的for_each 可以用std::apply 完成:

std::apply([](const auto&... args)
          {
              ((std::cout << args << std::endl), ...); // C++17 Fold expression
          }, t);

【讨论】:

  • 虽然std::for_each 确实如此,但所有其他不修改数据的 STL 算法都需要手动重写。为什么说迭代器与std::tuple 不兼容?我看到的唯一问题是,当您调用它的 operator++ 时,迭代器会更改其类型,我猜这没什么大不了的,因为您可能只是将它存储在不同的自动类型变量中,然后使用新变量递归调用 std::for_each作为“开始”参数。
  • “我看到的唯一问题是当你调用它的 operator++ 时迭代器会改变它的类型” 所以它不会是一个常规的迭代器,所以必须重写当前的算法.此外,大多数算法似乎“不适应”元组上的tuplestd::sortstd::min_element,这实际上会将橙色与苹果进行比较......如果你的元组是同质的,那么将其转换为(参考)数组可能是一个可行的解决方案。
  • 如果迭代器的定义可能需要扩展,并不意味着迭代器概念与std::tuple本身不兼容。所以问题仍然是:是否有任何语言限制阻止它存在,或者熟练的程序员(不幸的是我不是)可能能够重载一些 STL 算法以使它们也与std::tuple 一起工作?
  • 可以实现元组算法,但大多数算法对元组没有意义:什么会返回std::find(std::make_tuple(5, "Hello"), 42)
  • 在这种情况下会导致编译错误,因为接受std::stringintoperator== 没有重载。但是如果你的std::tuple 是用&lt;double, int, char&gt; 输入的,那将会编译。
【解决方案2】:

首先,元组本身不是容器。当然,您可以使用它们来存储数据,但它是完全(或至少可以)完全异构的。这给我们留下了一个问题,为什么要迭代异构数据?在大多数情况下,我认为没有理由。大多数情况下,当您迭代某些东西时,您希望使用迭代类型中的相似性来简化您对熟悉对象的工作。

当然,当您想迭代元组时,模板等的极端情况等等。但我想这些很少见,足以让标准地狱节省大量代码和模板魔法来实现我们想要的。无论如何,在boost fusion 中已经实现了这种迭代。也许有一天它会成为标准的一部分,就像以前的许多其他 boost 库一样。

【讨论】:

  • 您可能需要迭代异构数据的原因有很多。我很容易想到的一个是序列化。当然,您使用的函数必须具有所有必要的重载才能应用于存储在元组中的每种数据类型,但无论如何,这就是泛型编程的工作方式。所以问题是:在当前的标准特性下是不是不可能为std::tuple提供一个std::for_each重载,或者实际上是可能的,但没有人花时间去标准化它?
  • @nyarlathotep108 正如我所指出的,这在 C++ 中是可能的,甚至可以在 boost fusion 中完成。
  • 我看到了你的 boost fusion 的链接,我还是有一些疑问:因为它重新定义了每个容器,使它们成为异构的,我不确定他们对for_each 的实现是否可以被认为是std::for_each 的适当过载,这意味着我不确定它是否能够与普通的同质容器一起工作,例如 std::vectorstd::map 等。它看起来更像是仅针对异构容器的异构实现,就像实际上不可能为异构和同构类型的容器提供相同的功能。
猜你喜欢
  • 1970-01-01
  • 2015-01-07
  • 2014-08-31
  • 2021-05-16
  • 2022-08-23
  • 2016-11-11
  • 2023-02-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多