【问题标题】:Using std::tie as a range for loop target使用 std::tie 作为循环目标的范围
【发布时间】:2014-02-13 13:01:39
【问题描述】:

我想做如下的事情:

//std::vector<std::pair<TypeA, TypeB>> someInitializingFunction();
{
  TypeA a;
  TypeB b;

  for (std::tie(a, b) : someInitializingFunction()) {
    // do stuff;
  }
}

但是,这不是有效的代码,因为正如标准所说,基于范围的 for 循环被定义为等同于:

{
  auto && __range = range-init;
  for ( auto __begin = begin-expr,
      __end = end-expr;
      __begin != __end;
      ++__begin ) {
    for-range-declaration = *__begin;
    statement
  }
}

for-range-declaration 定义为:

范围声明: attribute-specifier-seq_{opt} decl-specifier-seq 声明符

那么让我退缩的是 decl-specifier-seq 没有​​标记为可选?

因此,我似乎必须为这个循环使用旧样式的循环:

std::vector<std::pair<TypeA, TypeB>> myList = someInitializingFunction();

{
  TypeA a;
  TypeB b;

  for (auto it = myList.begin(); it != myList.end(); ++it) {
    std::tie(a, b) = *it;
    // do stuff;
  }
}

但它在语法上似乎有点混乱,因为直觉上似乎是一个相当常见的任务,解包函数调用的结果,这在许多其他上下文中都是有效的。

有没有建议在语言中添加一些内容?这甚至是合理的想法吗?有没有更好的方法来做到这一点,我忽略了?我是否误读了标准?

显然,我可以组合自己的函数来执行此操作,但使用起来也有点混乱。

【问题讨论】:

标签: c++ for-loop language-lawyer std-pair tie


【解决方案1】:

截至 2017 年 3 月 21 日,结构化绑定是 C++ 的一部分。

这允许直接执行以下操作:

//std::vector<std::pair<TypeA, TypeB>> someInitializingFunction();
for (auto [a, b] : someInitializingFunction()) {
  // do stuff;
}

【讨论】:

  • "are part of C++" 好吧,c++ 标准并没有不断发展。它在版本中发布。所以,我想从这个日期开始,这注定要成为下一个 c++ 标准的一部分——我猜是 c++17。我在挑剔这个,因为遗憾的是我不会从 c++11 获得向后支持。无论如何 +1 以保持答案/问题是最新的。
  • 在 C++17 或更高版本中,这绝对是正确的答案——structured bindingsstd::tie() 更具可读性。
【解决方案2】:

你仍然可以使用 range-for!

//std::vector<std::pair<TypeA, TypeB>> someInitializingFunction();
{
  TypeA a;
  TypeB b;

  for (auto& p : someInitializingFunction()) {
    std::tie(a, b) = p;
    // do stuff;
  }
}

const auto&amp; p,如果您不需要/不想修改p

更新:使用上述方法,您还可以使用std::move将元素移动到绑定变量中

for (auto& p : someInitializingFunction()) {
  std::tie(a, b) = std::move(p);
  // do stuff;
}

您建议的语法可能无法很好地处理。一个人为的例子:

for (std::tie(a, b) : std::move(someInitializingFunction())) {}
// Note: std::move here is superfluous, as it's already an r-value
//    (may also hinder some optimizations). Purely for demonstration purposes.

这样,您无法将元素的值移动到绑定变量,因为来自 r 值容器的 begin()end() 等不会产生移动迭代器。 (嗯,是的,您可以将容器调整为返回移动迭代器的东西,但这将是一个全新的故事)

【讨论】:

  • 如果TypeATypeB 不是默认可构造的怎么办?
猜你喜欢
  • 2021-05-31
  • 2014-01-11
  • 1970-01-01
  • 2021-10-21
  • 1970-01-01
  • 1970-01-01
  • 2011-10-21
  • 1970-01-01
相关资源
最近更新 更多