20

While T&& is used with templates as forwarding reference or universal reference (as Scott Meyers calls them), I have seen some blogs use auto&& in code samples. I think auto itself should be enough, however, Herb Sutter in CppCon 2014 says: Never use auto&& for local variables

Why is that?

Seeing all replies , I feel I think I should have asked the contra. The general coding guidelines notwithstanding are there any good use cases of using auto&& inside a function body for code correctness and maintainability .

Asterisk
  • 397
  • 1
  • 2
  • 9
  • 1
    The `auto` keyword only infers the base type, not references (standard or "universal") or pointers or `const`. – Some programmer dude Oct 14 '14 at 07:54
  • @JoachimPileborg I get your point. But why never use it for local variables ? – Asterisk Oct 14 '14 at 08:04
  • 2
    @JoachimPileborg `auto` infers pointers just fine. But you're right about references and top-level `const`. – Angew is no longer proud of SO Oct 14 '14 at 08:06
  • 1
    To be specific, `auto` _decays_ the inferred type, just as template argument deduction would. – Xeo Oct 14 '14 at 09:25
  • 4
    There is nothing (well...) wrong with using `auto&&` for local variables (that's what the standard uses for range for loops). The idea is that the more implicit magic you put everywhere, the less clear it is what your program is doing, and the more likely it is that it is not doing what you expect. If you know something about a type but you make the compiler guess, it may not always guess what you expected, and it won't warn you about it. – Marc Glisse Oct 14 '14 at 13:02
  • 2
    @MarcGlisse I accept code clarity argument , but not compiler's guessing incorrectly. The compiler deduces correctly always. Let's take a use case. `auto&& ret = f(std::forward(t)); ` Say the t itself is accepted in the call to f by forwarding reference. The f is overloaded and may return either lvalue or rvalue reference. Basically if there is forwarding over multiple interfaces , it would be correct to use auto&& only or SomeTemplate&& if you know. Correct me if I am wrong . However I will assume Herb Sutter's advice as general usage guidelines with exceptions . More usecases appreciated – Asterisk Oct 14 '14 at 13:28
  • 1
    @MarcGlisse I would rather have the compiler "guess" than the programmer... – fredoverflow Oct 14 '14 at 13:32
  • I didn't say I agreed with Herb, just trying to guess what he may have meant. I didn't say the compiler was guessing incorrectly, but rather that the programmer had incorrect expectations, and the compiler couldn't warn the programmer because the programmer never wrote his expectations in the code. Also, Herb doesn't warn that `auto` (even without `&&`) should be avoided wherever there is a chance expression templates might be used. – Marc Glisse Oct 14 '14 at 13:48
  • @MarcGlisse If you see his slides , he makes strong arguments about using auto for correctness , maintainability , less typing in that order . Not sure why he's opposed to auto&& for local variables. – Asterisk Oct 14 '14 at 13:56
  • related: http://stackoverflow.com/questions/13230480/what-does-auto-tell-us and http://stackoverflow.com/questions/13241108/why-does-a-range-based-for-statement-take-the-range-by-auto – Piotr Skotnicki Oct 15 '14 at 12:27

3 Answers3

5

There are cases when you need a auto&& as a local, consider:

vector<bool> vb { true, false, true };
for( auto&& b : vb )
    b = !b;

Here, a auto& wouldn't do. (if vector<bool> is specialized)

However, the usual reason you use && together with type-deduction (ie a forwarding reference) is because you don't know or care of the exact type, you are just going to forward it.

The term 'universal reference' is a bit misleading, you should not use it universally, hence its changing name to 'forwarding reference'

Note that && not used with type-deduction is a rvalue reference, a different thing altogether.

Enlico
  • 23,259
  • 6
  • 48
  • 102
sp2danny
  • 7,488
  • 3
  • 31
  • 53
  • Why use it auto&& like that . I don't know if that would work. This is simpler for C++11 `for(auto b : vb) ` . In C++14 you can simply use `for(b : vb)` . – Asterisk Oct 14 '14 at 17:42
  • @Asterisk That wont cut it if its not specialized. `&&` works for both. Also, I think `for(b : vb)` is for c++17 – sp2danny Oct 14 '14 at 18:42
  • can you please clarify what do you imply by specialized here ? Probably some code to throw light on it would help. – Asterisk Oct 14 '14 at 18:46
  • I am not convinced. It has an iterator and const_iterator members like any container . auto should suffice. I would wait to see if somebody else agrees with you. – Asterisk Oct 14 '14 at 18:54
  • auto *do* suffice, for the specialized version. its the regular version that require a reference. – sp2danny Oct 14 '14 at 19:12
  • I believe you are alluding to something else. I think you mean you want the compiler to deduce whether b is a reference or value based on loop's body where the iterator - element is modified or not . If that is so , `for(auto & b : vb)` will work for all cases. Not only it is confusing to use auto&& in for loop (i am not sure if the compiler would give a warning) , it also gives a dangerous signal that you want to move b .Also even if the code works as expected , you can easily see if auto or auto& is more appropriate from loop's body.So it would be an abuse of auto&&. – Asterisk Oct 14 '14 at 20:12
  • 1
    @Asterisk : `for (auto& b : vb)` where `vb` is a `vector` will _not_ work -- have you even tried it? This answer _is_ correct... – ildjarn Oct 23 '14 at 04:05
  • @ildjarn My mistake , `for(auto b : vb) `will work .Or `for(const auto & b : vb)` will work depending on your choice. – Asterisk Oct 23 '14 at 04:53
  • 1
    @Asterisk : Not if you want to do `b = !b;` as in the answer... ;-] The **only** way that will work is with `auto&&`. – ildjarn Oct 23 '14 at 06:07
  • 1
    @Asterisk : The C++ standard mandates a specialization for `std::vector`; any standard library implementation without said specialization is broken, period. – ildjarn Oct 23 '14 at 06:56
  • 1
    @Asterisk `for (auto e : v)` will copy elements of `v`. `for (e : v)` is just an alias for `for (auto&& e : v)`. – Oktalist Oct 23 '14 at 13:37
  • So sad this is not accepted. – Enlico Nov 15 '22 at 13:58
-3

By using auto && we just missed the control over the variable storage. So we should never use such type of case. try to avoid it.

-4

I will concede there is one good enough case when you want to use range-for loop to modify contents of vector<bool>. However, I would recommend reading "On vector<bool>" by Howard Hinnant - the man responsible for rvalue references.

Apart from that aberration, there is no motivating example to show auto&& usage for local variables. Every local variable usage of auto&& is an abuse (what Sutter actually meant) except generic lambdas. By motivating I mean you cannot write optimal and correct code (no implicit conversions etc) without auto&&. You can use it just because you were waiting to use a nuclear weapon to kill a mouse. Let's consider some cases which arguably seem relevant.

  1. The range-based for statement is defined in §6.5.4 to be equivalent to:

    {
        auto && __range = range-init;
        for ( auto __begin = begin-expr, __end = end-expr;
              __begin != __end; ++__begin )
        {
            for-range-declaration = *__begin;
            statement
        }
    }
    

    Now this is purely theoretical. Let's do a thought experiment and say the compiler does this. Compilers are not known for high level implementation. Even if they do are you sure you can get one expression range-init to rule them all.

  2. My own specious argument of forwarding a forwarded reference across multiple interfaces. If you just want to forward why would you need auto&& named alias. Just forward.

  3. What if a function returns a universal reference. Really ?? Overloading on return type is disallowed. You can get it done via templates. However, in a related question the example passes T as template argument and also returns T. If you say T can be a rvalue or lvalue and I want to use auto&&, you have amnesia.

  4. Continuing 3, even if you hypothetically don't know whether you get T or T& from a black box (I would avoid such a box) you cannot get anything meaningful done without inferring whether it's an lvalue or rvalue. If you want to forward just forward.

  5. The for loop problem. Let me generalize it. Consider a general use case like for( auto x : {a, b , c}) or for(auto x : getVector()) or similar cases. You want to use for(auto&& b : vb) because vb may be a temporary and you may also want to modify the contents of the temporary. In my finite wisdom I don't understand why you would want to modify the contents of a temp vector or list. You can keep coming up with arguments like the next item may depend on the modified previous value etc , but you can come up with an optimal solution without auto&&. Personally I believe modifying a temporary's contents without binding it to a const T& should be outlawed.

  6. The variadic template argument. I dreamt that if I need to peel the first argument from var... I may want to use auto&& or T&&. I don't think even this holds water. Advise me if there can be a plausible case.

  7. I want an auto&& to bind something. Then use it in for loop. Simply use it inside for loop.

  8. The killer argument if you really bring up a good enough case except lambdas: You cannot write enough lines without determining or fixing it as T or T&. Otherwise because you want to write optimal code you will have code bloat ...for every line you write you will have to check if rvalue do this else if rvalue do that. Better to use type traits at the beginning to determine r/l-valueness.

Please add new specious or good use cases if you come across any.

dyp
  • 38,334
  • 13
  • 112
  • 177
Asterisk
  • 397
  • 1
  • 2
  • 9
  • 2
    its not the vector that's a temporary, it's what you get when you dereference the iterator that is a lvalue for vector but a rvalue for vector. thus, if you have a vector of T, auto&& is the only option that covers both – sp2danny Oct 23 '14 at 06:47
  • @sp2danny I wasn't using the vector as example. Please do not see the answer as a reply to your answer. I meant a general use case like `for( auto x : {a, b , c})` or similar case `for(auto x : getVector())` or such cases. – Asterisk Oct 23 '14 at 06:52
  • 1
    but `vector` is only one example of when dereferencing an iterator may give you a rvalue proxy class that only behave as an reference. you **want** to forward that as is, hence you need a forwarding reference for range based for in those cases – sp2danny Oct 23 '14 at 07:07
  • 4
    my eyes hurt from this huge wall of text. consider editing it – BЈовић Oct 23 '14 at 07:18
  • @sp2danny I am scavenging SO and the world for `vector<bool>` and hope to come up with something good. By the way can you vouch the code compiles ( and iterator of vector<bool> cannot be dereferenced to lvalue , implying it is specialized implementation) and the value actally changes by `b = !b;` in your code ? – Asterisk Oct 23 '14 at 07:23
  • @sp2danny I concede you're right. I will upvote and modify my answer. However I am against marking your answer correct because the question itself has become philosophical. – Asterisk Oct 23 '14 at 08:39
  • 1
    Sorry, but I could not read it with the original formatting. So I tried to improve it. – dyp Oct 23 '14 at 10:04