C++ 在基于范围的for循环中使用转发引用的优点是什么?

C++ 在基于范围的for循环中使用转发引用的优点是什么?,c++,performance,for-loop,c++11,move-semantics,C++,Performance,For Loop,C++11,Move Semantics,如果我想执行只读操作,const auto&就足够了。然而,我遇到了 for (auto&& e : v) // v is non-const 最近有几次。这让我想知道: 与auto&或const auto&相比,在一些模糊的情况下,使用转发引用是否可能有一些性能优势 (shared_ptr是不明角落案件的嫌疑人) 更新 我在收藏夹中找到了两个示例: 请集中讨论以下问题:为什么我要使用基于范围的自动和&in循环?我能看到的唯一优势是序列迭代器返回代理引用,并且您需要以非

如果我想执行只读操作,
const auto&
就足够了。然而,我遇到了

for (auto&& e : v)  // v is non-const
最近有几次。这让我想知道:

auto&
const auto&
相比,在一些模糊的情况下,使用转发引用是否可能有一些性能优势

shared_ptr
是不明角落案件的嫌疑人)


更新 我在收藏夹中找到了两个示例:



请集中讨论以下问题:为什么我要使用基于范围的自动和&in循环?

我能看到的唯一优势是序列迭代器返回代理引用,并且您需要以非常量方式对该引用进行操作。例如,考虑:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    for (auto& e : v)
        e = true;
}
尽管如此,除非您知道需要满足这样的用例,否则我不会以这种方式编码。也就是说,我不会无缘无故地这样做,因为这确实会让人们怀疑你在干什么。如果我真的这么做了,那么在评论中加入原因也无妨:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    // using auto&& so that I can handle the rvalue reference
    //   returned for the vector<bool> case
    for (auto&& e : v)
        e = true;
}
#包括
int main()
{
std::向量v(10);
//使用auto&&以便处理右值引用
//返回向量案例
用于(自动和e:v)
e=真;
}
编辑


我的最后一个案例应该是一个有意义的模板。如果您知道循环总是在处理代理引用,那么
auto
将与
auto&
一样工作。但是,当循环有时处理非代理引用,有时处理代理引用时,我认为
自动&&
将成为首选解决方案。

使用
自动&&
或使用基于范围的
for
-循环的优点是,您可以捕获您得到的内容。对于大多数类型的迭代器,对于某些类型的
T
,您可能会得到
T&
T常量&
。有趣的例子是,在迭代中解迭代器产生临时的:C++ 2011得到了松弛的要求,迭代器不一定需要产生一个LValk。通用引用的使用与
std::for_each()
中的参数转发相匹配:


当然,使用
std::forward()
意味着您接受要从中移动的任何返回值。像这样的对象在非模板代码中是否有意义,我还不知道。我可以想象,使用通用引用可以为编译器提供更多的信息,从而做出正确的事情。在模板化代码中,它不做任何关于对象应该发生什么的决定。

我几乎总是使用
auto&
。既然你不需要,为什么还要被边缘的箱子咬呢?打字也比较短,我只是觉得它更。。。透明的。当你使用
auto&&x
时,你就会知道
x
每次都是
*它

你真的“经常”看到它吗?我不确定你的问题中是否有足够的上下文让我来判断它有多“疯狂”这就是你看到的地方。@LightnessRacesinOrbit长话短说:我为什么要在基于范围的for循环中使用
auto&&
?另一方面,没有明显的缺点,不是吗?(除了可能让人困惑之外,我个人认为这一点不值得一提。)另一个不必要地让人困惑的编写代码的术语是:编写混乱的代码。最好使代码尽可能简单,但不要简单。这将有助于保持错误倒计时。这就是说,随着&&变得越来越熟悉,那么也许5年后人们会期待一个自动&&习惯用法(假设它实际上没有伤害)。我不知道这是否会发生。但简单在旁观者的眼里,如果你写的不仅仅是你自己,考虑到您的读者。我更喜欢
const auto&
当我希望编译器帮助我检查我是否无意中修改序列中的元素时。我个人喜欢在需要修改序列元素的通用代码中使用
auto&
。如果我不这样做,我会坚持<代码> Autoconst和。@ Xeo:+ 1,这是因为像你这样的狂热爱好者,不断地尝试和推动更好的做事方式,C++继续进化。谢谢。:-)我的问题是,如果
const auto&
足够的话,你就放弃了
const
-ness的
auto&&
。这个问题问的是我可能被咬的角落案例。Dietmar或Howard还没有提到的角落案例有哪些?如果你使用
auto&
,这里有一种被咬的方法。如果您要捕获的类型应该在循环体中移动(例如),并更改为更晚的日期,以便将其解析为
常量&
类型,则您的代码将以静默方式继续运行,但您的移动将被复制。这种代码将非常具有欺骗性。但是,如果您显式地将该类型指定为r值引用,那么无论是谁更改了容器类型,都会得到一个编译错误,因为您确实希望移动而不是复制这些对象…@cyberbisson我刚刚遇到一个问题:如果不显式地指定类型,我如何强制执行右值引用?类似于(std::decation\t&&e:v)的
?我想有更好的方法…@JerryMa,这取决于你对这种类型的了解。如上所述,
auto&
将提供一个“通用参考”,因此除此之外的任何内容都将为您提供一个更具体的类型。如果假定
v
向量
,则可以执行
decltype(v)::value\u type&&
,这是我假设您希望通过在迭代器类型上获取
运算符*
的结果。您还可以执行
decltype(begin(v))::value\u type&
来检查迭代器的类型,而不是容器。但是,如果我们对该类型的了解如此之少,我们可能会
#include <vector>

int main()
{
    std::vector<bool> v(10);
    // using auto&& so that I can handle the rvalue reference
    //   returned for the vector<bool> case
    for (auto&& e : v)
        e = true;
}
template <typename InIt, typename F>
F std::for_each(InIt it, InIt end, F f) {
    for (; it != end; ++it) {
        f(*it); // <---------------------- here
    }
    return f;
}
for (auto&& x: range) {
    f(std::forward<decltype(x)>(x));
}