【问题标题】:What are "terse ranged-based for loops"?什么是“基于范围的简洁 for 循环”?
【发布时间】:2014-08-24 04:18:10
【问题描述】:

clang 已开始从 n3994 实现 terse ranged-based for loops。通常在引入基于范围的 for 循环时,我们会看到 for (auto & v : vector) 形式的代码,以避免不必要的复制。似乎 n3994 提议 for (auto && v : vector) 在各方面都优越。我有几个问题:

  1. 后一种形式比前一种有什么优势?如果 auto && 明显有优势,为什么我们通常会选择 auto & 而不是 auto &&?
  2. 是否使新的基于范围的循环等效于auto && 会破坏现有代码?它会对新代码产生实际影响吗?
  3. 这不会向初学者介绍他们的代码实际上等同于auto && 的问题吗?

【问题讨论】:

  • 它不能破坏现有代码;现有语法不适合。
  • 请注意,该提案“被厄巴纳的全体委员会拒绝。作者将进行修改。”

标签: c++ c++17


【解决方案1】:

后一种形式比前一种有什么优势?

在for(auto& v : vector) 的形式中,v 的类型被推断为对通过取消引用容器的迭代器类型获得的类型的左值引用。这意味着如果取消引用迭代器的结果是一个右值(想想std::vector<bool>,它返回一个代表对单个bool 值的引用的代理类型),那么代码将无法编译,因为左值引用无法绑定到一个右值。

当您编写for(auto&& v : vector) 时,这是一个通用引用,这意味着v 的类型将在上述情况下被推导出为右值引用;或者在取消引用迭代器返回对容器元素的引用的通常情况下作为左值引用。所以它也适用于vector<bool> 的情况。这就是为什么如果您计划修改循环内迭代的元素时应该首选该表单的原因。

如果 auto&& 明显有优势,为什么我们通常会选择 auto& 而不是 auto&&?

你不应该。我能想到auto&& 的唯一缺点是它不能保证您对元素所做的更改一定会传播回容器,但这表明设计有问题,我认为不值得保护反对。

是否使新的基于范围的循环等效于auto && 会破坏现有代码?

我看不出它如何破坏现有代码,因为旧语法将继续像今天一样发挥作用。但是,如果您的意思是用新语法替换现有代码,那么如果您要替换的代码是 auto const& 表单,它可能会产生影响。见this example。注意auto const& 版本如何调用const 成员函数,而另外两个调用非const 版本?用简洁的版本替换第一个将改变被调用的成员函数。

它会对新代码产生实际影响吗?

同样,它与今天使用 auto&& 的旧代码没有什么不同,因此不会有任何区别。如果您在不打算修改元素的地方使用它,那么编译器将不再阻止您意外地这样做,并且您可能会调用不同的重载,如上例所示。

这不会向初学者介绍他们的代码实际上等同于auto &&吗?

我不确定我理解你的意思,但如果你问初学者是否会在不知道的情况下编写代码,或者了解引用折叠的复杂性,那么是的,他们可能会。但这是您所链接的论文的既定目标之一。论点是,您可以远离一开始就教授那些困难的概念,而是向初学者介绍一种适用于所有内容的基于范围的for 循环的单一语法。就这一点而言,我认为语法有优点,但从const 正确性的角度来看,我不赞成它,因为如果我想要对元素进行只读访问,我宁愿使用auto const&,然后简洁的语法看起来是不对称的。

【讨论】:

  • 又是那个讨厌的vector<bool>。我想我在使用vector<bool>时被auto& v: vector咬过一次。
  • W/r/t 最后一点,我想他们可以介绍类似for(const elem : range)...
  • @T.C.那样就好了。 Stephan 甚至将确切的语法列为一种可能性,但出于某种原因,并未将其包含在提案中。
  • " 它不保证您对元素所做的更改一定会传播回容器,但这表明设计有问题" - 如果容器要求更改为有保证,还是有充分的技术原因不能保证?
【解决方案2】:

后一种形式比前一种有什么优势?为什么我们通常使用auto & 而不是auto && 如果后者是 明显有优势?

auto & 如果取消引用迭代器返回代理对象而不是实际引用,则不起作用,因为您将尝试将非 const 左值引用绑定到临时引用。标准的例子是被称为std::vector<bool>的可憎之物;取消引用它的迭代器会返回一个std::vector<bool>::reference 类型的代理对象,它代表向量中的一个位。由于大多数迭代器返回实际引用,因此您不会经常遇到此问题。

是否使新的基于 ranged-for 的循环等效于 auto && 会破坏现有代码?它会对新代码产生实际影响吗?

不,因为新语法 for(elem : range) 无法在现有代码中编译。

这不会向初学者介绍他们的代码实际上等同于auto &&吗?

为什么会有问题? auto && 的好处是它实际上适用于所有事物。有人可能会争辩说,不必教初学者有关类型推断和引用折叠等的所有细节实际上是一个优点,因为它使语言更容易学习。

【讨论】:

    猜你喜欢
    • 2016-10-31
    • 1970-01-01
    • 2014-12-06
    • 2014-01-12
    • 2013-01-04
    • 1970-01-01
    • 1970-01-01
    • 2019-06-01
    • 1970-01-01
    相关资源
    最近更新 更多