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

Ali picture Ali · Oct 29, 2012 · Viewed 24.8k times · Source

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

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&?

(shared_ptr is a suspect for obscure corner cases)


Update Two 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?

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

Answer

Howard Hinnant picture Howard Hinnant · Oct 29, 2012

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>::reference returned from the iterator won't bind to a non-const lvalue reference. But this will work:

#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 does cause 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 auto would 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.