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

use*_*004 19 c++ c++17

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

  1. 后者形式比前者有什么优势?为什么我们通常不去,auto &而不是auto &&后者显然有利?
  2. 是否使新的基于范围的循环等效auto &&于破坏现有代码?它会对新代码产生实际影响吗?
  3. 难道这不会给初学者带来他们的代码实际等同的问题auto &&吗?

Pra*_*ian 10

后者形式比前者有什么优势?

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

当你写作时for(auto&& v : vector),这是一个通用的引用,意思是v在上述情况下,将推导出一个rvalue引用的类型; 或者作为通常情况下的左值引用,其中解引用迭代器返回对容器元素的引用.所以它也适用于这种vector<bool>情况.这就是为什么如果你计划修改你在循环中迭代的元素,那么这个表格应该是首选的.

为什么我们通常不去,auto&而不是auto&&后者显然有利?

你不应该.我能想到的唯一缺点auto&&是,它不能保证你对元素所做的更改必然会传播回容器,但这表明设计已经破损,我认为不值得保护.

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

我没有看到它如何破坏现有代码,因为旧语法将继续像今天一样运行.但是,如果您的意思是使用新语法替换现有代码,那么如果您要替换的是auto const&表单,则可能会产生影响.看这个例子.注意auto const&版本如何调用const成员函数,而另外两个调用非const版本?用简洁版替换第一个将更改被调用的成员函数.

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

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

难道这不会给初学者带来他们的代码实际等同的问题auto &&吗?

我不确定我理解你的意思,但是如果你问初学者是否会在不知情的情况下编写代码,或者理解参考文件崩溃的复杂性,那么是的,他们可能会这样做.但这是你所链接的论文的既定目标之一.争论的焦点是,您可以在开始时远离教授这些困难的概念,但是将初学者引入基于范围的for循环的单一语法,该循环适用于所有内容.就这一点而言,我认为语法具有优点,但从const正确的角度来看它,我不好意思,因为我宁愿使用,auto const&如果我想要对元素进行只读访问,那么简洁的语法似乎不对称的.


T.C*_*.C. 8

后者形式比前者有什么优势?为什么我们通常不去,auto &而不是auto &&后者显然有利?

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

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

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

难道这不会给初学者带来他们的代码实际等同的问题auto &&吗?

为什么会这样?auto &&它的好处是它实际上适用于一切.有人可能会争辩说,不必教初学者所有关于类型演绎和参考折叠等的细节实际上是一个加分,因为它使语言更容易学习.