Auto Type Deduction in Range-Based For Loops

Range-based For Loops offer a nice way to loop over the elements of a container. In combination with Auto Type Deduction the source code will become very clean and easy to read and write.

for (auto element : container) 
{ 
    // ...
}

The Auto Type Deduction is available in different variants:

  • auto
  • const auto
  • auto&
  • const auto&
  • auto&&
  • const auto&&
  • decltype(auto)

Of course, these variants result in different behaviors and you should choose the right one according to your needs. Following I will give a short overview of these variants and explain their behavior and standard use case.

auto

This will create a copy of the container element. This variant is used in case you want to get and modify the element content, for example to pass it to e function, but leave the origin container element as it is.

const auto

Like in the first variant, this creates a copy of the element content. But this time this copy is constant and cannot be changed. In most cases “const auto” isn’t a good choice. If you want to work with an immutable copy you can use “const auto&” too and don’t have to create a copy. There are a few use cases for this variant only. For example, it could be useful in multithreading scenarios. Let’s say you want to use the element several times within the loop. But in parallel another thread may change the container element. By using “const auto” you create a copy of the element and can use this copy in your loop several times. If you use “const auto&” you will get the updated element instead. So, there are scenarios where “const auto” and “const auto&” create different results. Therefore, we have a need for “const auto” even if it is used very rarely.

auto&

This will create a reference to the original container element. So, it is used in case you want to modify the container content.

const auto&

This creates a constant reference to the original container element. So that’s the perfect choice if you need read-only access to the elements.

auto&&

Like “auto&” this variant with double “&” is used in case you want to modify the origin container elements. There are some special cases where it isn’t possible to use the normal “auto&” variant. For example a loop over “std::vector<bool>” yields a temporary proxy object, which cannot bind to an lvalue reference (auto&). In such cases “auto&&” can be used. It is a forwarding reference. If it is initialized with an lvalue, it creates an lvalue reference and if it is initialized with an rvalue, it creates an rvalue reference. As a result, “auto&&” is a good candidate for generic code and therefore it is most often used in templates.

Of course, as the forwarding reference “auto&&” covers the use cases of the standard reference “auto&” we may ask ourselves if we should ever use the variant with the double “&”. But I would not recommend this. The syntax with double “&” is more confusing. Developers are familiar with the standard reference syntax and will expect the forward reference syntax in special cases only. So, I recommend using “auto&” outside of templates and “auto&&” within templates.

const auto&&

This creates a read-only forwarding reference. This variant will bind to rvalues only. A read-only access will work for containers which yield a temporary proxy object. So in contrast to a read-access we don’t have to use the double “&” variant for containers like “std::vector<bool>”. There are only a view theoretical use cases for “const auto&&” and therefore you will normally not use this variant for your applications.

decltype(auto)

This variant should not be used in Range-Based For Loop. “decltype(auto)” is primarily useful for deducing the return type of forwarding functions. Use it to declare a local variable is an antipattern. Therefore, I don’t want to get in detail about “decltype” and just mentioned it for completeness. Even if the compiler allows to write “decltype(auto)” you should not use it in Range-Based For Loops.

Summary

  • Use “auto” when you want to work with a copy of the elements
  • Use “auto&” when you want to modify elements
  • Use “auto&&” when you want to modify elements in generic code
  • Use “const auto&” when you want read-only access to elements
  • Use “const auto” in multithreading scenarios when you need read-only access to volatile elements
Werbeanzeigen
Dieser Beitrag wurde unter C++ veröffentlicht. Setze ein Lesezeichen auf den Permalink.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google Foto

Du kommentierst mit Deinem Google-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s