使用std :: tie作为循环目标的范围

Omn*_*ity 24 c++ for-loop tie language-lawyer std-pair

我想做类似以下的事情:

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

  for (std::tie(a, b) : someInitializingFunction()) {
    // do stuff;
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

其中for-range-declaration定义为:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

但是在语法上看起来似乎有些混乱似乎是一个相当常见的任务,解包函数调用的结果,这在许多其他上下文中都是有效的.

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

显然,我可以把我自己的功能放在一起做这个,但是使用它也有点麻烦.

Mar*_*cia 16

你仍然可以使用range-for!

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

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

或者,const auto& p如果您不需要/想要修改p.

更新:通过上述内容,您还可以使用将元素移动到绑定变量std::move

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

您提出的语法可能无法很好地处理.一个人为的例子:

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.
Run Code Online (Sandbox Code Playgroud)

就这样,你不必元素的值移到绑定变量,如能力begin(),end()从R值容器等不会产生移动迭代器.(嗯,是的,你可以将容器调整为返回移动迭代器的东西,但这将是一个全新的故事)

  • 如果`TypeA`和`TypeB`不是默认构造的怎么办? (6认同)

Omn*_*ity 11

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

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

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

  • "*是C++*的一部分"很好的c ++标准并没有持续发展.它是在版本中发布的.所以,我想在这个日期,这注定要成为下一个c ++标准的一部分 - 我想是c ++ 17.我正在挑剔这个,因为遗憾的是我不会得到c ++ 11的后退支持.无论如何+1保持答案/问题是最新的. (3认同)