54

Assuming my current rule when programming with range-based loops says

Use for(auto const &e :...) or for(auto &e:...) when possible over for(auto a: ...).

I base this on my own experience and this question for example.

But after reading about the new terse for loops I wonder, should I not replace my & in my rule with &&? As written here this looks like the Meyers' Universal References.

So, I ask myself, should my new rule either be

Use for(auto const &&e :...) or for(auto &&e:...) when possible ...

or does that not always work and therefore should rather be the quite complicated one

Check if for(auto const &&e :...) or for(auto &&e:...) is possible, then consider for(auto const &e :...) or for(auto &e:...), and only when needed do not use references.

18
  • 1
    auto && always works. That's why it's "universal". If necessary, the deduced type will be qualified. Commented Nov 18, 2014 at 10:00
  • 3
    const auto&& is not a forwarding reference, it's const rvalue reference Commented Nov 18, 2014 at 10:06
  • 1
    and the rest is explained in N3853 and What is the advantage of using universal references in range-based for loops? Commented Nov 18, 2014 at 10:10
  • 2
    @Bulletmagnet it was STL during CppCon'14 Commented Nov 18, 2014 at 12:27
  • 3
    @PiotrS. Cunningham's Law states "the best way to get the right answer on the Internet is not to ask a question, it's to post the wrong answer." Commented Nov 18, 2014 at 14:08

1 Answer 1

18

When and if you should use auto&& in for loops has been explained very nicely by Howard Hinnant here.

This leaves the question what x in

auto &&x = ...expr... 

actually is. And it is handled as if there there were a function template definition

template <class U> void f(U&& u); 

and the type of x is deduced by the same rules as u [§7.1.6.4.(7)].

This means it is not handled as a RValue Reference, but as a "Universal/Forwarding Reference" -- the "Reference Collapsing Rules" apply.

This also holds for

const auto &&x = ...expr... 

as the example in §7.1.6.4.(7) states, at least for const auto &x.

But, as PiotrS says in the questions comments, any qualifiers nullifies the URef-ness:

no, because neither T in template<class T> void f(const T&&) is a forwarding reference, nor const auto&& is. The fact that T&& occurs in parameter declaration does not imply it is forwarding reference. Only pure T&& with no qualifiers like const or volatile is forwarding reference, meaning it has to be template<class T> void f(T&&) or auto&&, and never const T&& or const auto&&

Sign up to request clarification or add additional context in comments.

3 Comments

For Forward reference, it should be template <class U> void f(U&& u); not template <class U> void f(const U& u);
"nullifies the URef-ness" is highly misleading... reference collapsing happens for const T&& just as it does for T&&. It is no longer "universal" because half the types in the universe (the ones not const qualified) cannot be matched, but it behaves much the same.
@BenVoigt It's not just qualification. A const auto&& declarator or the u in template<class U> void f(const U&& u); can never automatically deduce type from any lvalue. The special rule which makes it valid for a true forwarding reference (and indirectly for the exact type auto&&) no longer applies.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.