C++ 在基于范围的 for 循环中使用转发引用有什么好处?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13130708/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:00:23  来源:igfitidea点击:

What is the advantage of using forwarding references in range-based for loops?

c++performancefor-loopc++11move-semantics

提问by Ali

const auto&would suffice if I want to perform read-only operations. However, I have bumped into

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

for (auto&& e : v)  // v is non-const

a couple of times recently. This makes me wonder:

最近几次。这让我想知道:

Is it possible that in some obscure corner cases there is some performance benefit in using forwarding references, compared to auto&or const auto&?

auto&或相比,在一些晦涩的角落情况下,使用转发引用是否有可能带来一些性能优势const auto&

(shared_ptris a suspect for obscure corner cases)

shared_ptr是模糊的极端情况的嫌疑人)



UpdateTwo examples that I found in my favorites:

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

Any disadvantage of using const reference when iterating over basic types?
Can I easily iterate over the values of a map using a range-based for loop?

在迭代基本类型时使用 const 引用有什么缺点吗?
我可以使用基于范围的 for 循环轻松迭代地图的值吗?

Please concentrate on the question: why would I want to use auto&& in range-based for loops?

请专注于这个问题:为什么我要在基于范围的 for 循环中使用 auto&& ?

采纳答案by Howard Hinnant

The only advantage I can see is when the sequence iterator returns a proxy reference and you need to operate on that reference in a non-const way. For example consider:

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

#include <vector>

int main()
{
    std::vector<bool> v(10);
    for (auto& e : v)
        e = true;
}

This doesn't compile because rvalue vector<bool>::referencereturned from the iteratorwon't bind to a non-const lvalue reference. But this will work:

这不会编译,因为vector<bool>::reference从 返回的右值iterator不会绑定到非常量左值引用。但这会起作用:

#include <vector>

int main()
{
    std::vector<bool> v(10);
    for (auto&& e : v)
        e = true;
}

All that being said, I wouldn't code this way unless you knew you needed to satisfy such a use case. I.e. I wouldn't do this gratuitously because it doescause people to wonder what you're up to. And if I did do it, it wouldn't hurt to include a comment as to why:

话虽如此,除非您知道需要满足这样的用例,否则我不会以这种方式编码。也就是说,我不会无缘无故地这样做,因为它确实会让人们怀疑你在做什么。如果我这样做了,包含关于原因的评论也无妨:

#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;
}

Edit

编辑

This last case of mine should really be a template to make sense. If you know the loop is always handling a proxy reference, then autowould work as well as auto&&. But when the loop was sometimes handling non-proxy references and sometimes proxy-references, then I think auto&&would become the solution of choice.

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

回答by Dietmar Kühl

Using auto&&or universal referenceswith a range-based for-loop has the advantage that you captures what you get. For most kinds of iterators you'll probably get either a T&or a T const&for some type T. The interesting case is where dereferencing an iterator yields a temporary: C++ 2011 got relaxed requirements and iterators aren't necessarily required to yield an lvalue. The use of universal references matches the argument forwarding in std::for_each():

在基于范围的循环中使用auto&&通用引用for的优势在于您可以捕获所获得的内容。对于大多数类型的迭代器,您可能会为某些类型获得 aT&或 a 。有趣的情况是取消引用迭代器会产生一个临时的:C++ 2011 有宽松的要求,迭代器不一定需要产生左值。通用引用的使用与 中的参数转发相匹配:T const&Tstd::for_each()

template <typename InIt, typename F>
F std::for_each(InIt it, InIt end, F f) {
    for (; it != end; ++it) {
        f(*it); // <---------------------- here
    }
    return f;
}

The function object fcan treat T&, T const&, and Tdifferently. Why should the body of a range-based for-loop be different? Of course, to actually take advantage of having deduced the type using universal references you'd need to pass them on correspondingly:

该函数对象f可以治疗T&T const&以及T不同。为什么基于范围的for循环的主体应该不同?当然,要真正利用使用通用引用推断类型的优势,您需要相应地传递它们:

for (auto&& x: range) {
    f(std::forward<decltype(x)>(x));
}

Of course, using std::forward()means that you accept any returned values to be moved from. Whether objects like this makes much sense in non-template code I don't know (yet?). I can imagine that using universal references can offer more information to the compiler to do the Right Thing. In templated code it stays out of making any decision on what should happen with the objects.

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

回答by Puppy

I virtually always use auto&&. Why get bitten by an edge case when you don't have to? It's shorter to type too, and I simply find it more... transparent. When you use auto&& x, then you know that xis exactly *it, every time.

我几乎总是使用auto&&. 为什么在不必要的情况下会被边缘情况咬伤?打字也更短,我只是觉得它更......透明。当您使用auto&& x,那么您知道x到底是*it,每一次。