16

Is there a situation when decltype(auto) would be a better choice than auto (possibly with &, &&, or cv qualifiers) when using range-based for loops? In other words, would you ever write the following code?

for (decltype(auto) item : range) {
    // ...
}
s3rvac
  • 9,301
  • 9
  • 46
  • 74

2 Answers2

11

decltype(auto) generates a different type when the input iterator returns by value. auto&& creates an rvalue reference to the temporary, while decltype(auto) creates a local copy (in C++17 it just names the temporary because of the guaranteed elision change).

This has little difference. In C++11/14, it requires a move ctor (that is not called in practice, but required) in the decltype(auto) case, but not in C++17. In the auto&& the move ctor is not called and not required.

Another difference is the type of decltype(item), which is a reference always with auto&&, but in the case of the temporary returning input iteraror decltype(item) is a value type.

That is about it. In practice, I see no reason to decltype(auto) over auto&&.

As an aside, auto& forces non-rvalue, const auto& forces non-mutable, and auto forces a copy. There are reasons to use auto&& instead of those, but that is outside the scope of this question. decltype(auto) is closest to auto&&, so I compared those two.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • 1
    `auto&&` is an rvalue reference here? I thought it was a universal/forwarding reference. Not claiming you're wrong--just trying to learn. :) – erip Jul 17 '16 at 16:59
  • 2
    @erip : It is indeed a forwarding reference – "when the input iterator returns by value" then it creates an rvalue reference. ;-] – ildjarn Jul 17 '16 at 17:08
  • Totally overlooked that. Oops! – erip Jul 17 '16 at 17:10
3

As mentioned here:

decltype(auto) is primarily useful for deducing the return type of forwarding functions and similar wrappers

[...]

although it can be used to declare local variables, doing that is probably just an antipattern since a local variable’s reference-ness should not depend on the initialization expression

That said, using a forwarding reference in a range-based for loop is the way to go.
As mentioned here:

It is safe, and in fact, preferable in generic code, to use deduction to forwarding reference

I'd suggest this question on SO for further details about using an universal reference in a range-based for loop.

Community
  • 1
  • 1
skypjack
  • 49,335
  • 19
  • 95
  • 187
  • 1
    "*Apart for the fact that they are currently named universal reference, the note is still valid.*" You have that backwards – Meyers gave them the ad hoc name 'universal references', but starting with C++17 the standard itself formally names them 'forwarding references'. – ildjarn Jul 17 '16 at 14:04
  • @ildjarn And you **are absolutely right**. I'm going to fix the answer. I ever mistake the two forms. Sorry and thank you. – skypjack Jul 17 '16 at 14:05