什么是"简洁的基于范围的for循环"?

19
clang已开始实现简洁的基于范围的for循环,源自n3994。通常在引入基于范围的for循环时,我们看到的代码形式为for (auto & v : vector)以避免不必要的复制。似乎n3994提出for (auto && v : vector)在各个方面都更加优越。我有几个问题:
  1. 后一种形式相对前一种形式有哪些优势?如果后者明显更有优势,为什么我们通常选择auto &而不是auto &&
  2. 使新的基于范围的for循环等同于auto &&会破坏现有代码吗?它会对新代码产生实际影响吗?
  3. 这难道不会向初学者介绍一个陷阱,让他们的代码实际上等同于auto &&

2
它不能破坏现有的代码;现有的语法不适合。 - chris
请注意,这个提案在厄巴纳全委会上被“否决”。作者将进行修订。 - sp2danny
2个回答

10
后者相比前者有什么优势? 在形式上,for(auto& v : vector),变量v的类型被推断为对容器迭代器类型解引用后得到的左值引用类型。这意味着如果解引用迭代器的结果是一个右值(例如std::vector<bool>返回代表单个bool值的代理类型),那么代码将无法编译,因为左值引用不能绑定到右值。 当你写for(auto&& v : vector)时,这是一个"万能引用",这意味着v的类型将被推断为右值引用,在上述情况下,或者在通常情况下,即解引用迭代器返回对容器元素的引用时,将被推断为左值引用。所以它也适用于vector<bool>案例。这就是为什么如果你打算在循环中修改正在迭代的元素,应该使用后一种形式。
为什么我们通常选择auto&而不是auto&&,如果后者明显更有优势? 你不应该。我能想到的唯一缺点是auto&&不能保证对元素所做的更改一定会传播回容器,但这表明设计存在问题,我认为没有必要进行保护。
让新的基于范围的循环等价于auto &&会破坏现有代码吗?

我不认为这种语法会破坏现有代码,因为旧的语法仍然像今天一样运行。但如果你的意思是用新的语法替换现有的代码,那么如果你要替换的是auto const&形式,就可能会有影响。请参见这个例子。注意auto const&版本调用了const成员函数,而其他两个调用了非const版本?用简洁的语法替换第一个将更改被调用的成员函数。

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

同样地,没有任何不同的是今天使用auto&&的旧代码,所以它不会有任何影响。如果你在不想修改元素的地方使用它,那么编译器将不再阻止你意外地对其进行修改,并且你可能会调用不同的重载,就像上面的示例一样。

这不会给初学者带来问题吗,他们的代码实际上等价于auto &&

我不确定你的意思是什么,但如果你在问初学者是否会不知道或不理解引用折叠的复杂性就编写代码,那么是的,他们可能会。但这是你链接的论文中明确提出的目标之一。论点是你可以避免一开始就教授这些困难的概念,而是向初学者介绍一种适用于所有内容的单一语法范式for循环。就这方面而言,我认为这种语法有优点,但从const正确性的角度来看,我对它持谨慎态度,因为如果我想要只读访问元素,我更愿意使用auto const&,然后简洁的语法看起来不对称。


那个讨厌的 vector<bool> 又出现了。我想当我使用 vector<bool> 时,曾经被 auto& v: vector 咬过一次。 - R Sahu
关于最后一点,我想他们可以引入类似 for(const elem : range) 这样的东西... - T.C.
@T.C. 那会很好。Stephan甚至将该语法列为可能性,但出于某种原因,没有将其包含在提案中。 - Praetorian
“这并不保证您对元素所做的更改一定会传播回容器,但这表明设计存在问题” - 是否应更改容器要求以保证这一点,或者是否存在良好的技术原因导致无法保证? - Steve Jessop

8
后一种形式相对于前一种形式有什么优势?如果后者明显更有优势,为什么我们通常选择auto &而不是auto &&
如果解引用迭代器返回代理对象而不是实际引用,则auto &无法工作,因为您将尝试将非const左值引用绑定到临时对象。标准示例是被称为std::vector<bool>的可怕东西;解引用它的迭代器会返回std::vector<bool>::reference类型的代理对象,该对象表示向量中的单个位。由于大多数迭代器返回实际引用,因此您不经常遇到此问题。
使新的基于范围的for循环等效于auto &&会破坏现有代码吗?它会对新代码产生实际影响吗?
不会,因为新语法for(elem : range)在现有代码中不会编译。
这是否会向初学者介绍一个陷阱,即他们的代码实际上等同于auto &&
为什么会是陷阱呢?auto &&的好处是它可以适用于所有情况。有人可能会认为,不需要教初学者有关类型推断和引用折叠等所有细节实际上是一种优点,因为它使语言更易于学习。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接