Click here to Skip to main content
15,884,177 members
Articles / All Topics
Technical Blog

C++: auto

Rate me:
Please Sign up or sign in to vote.
4.88/5 (4 votes)
31 May 2015CPOL12 min read 7.7K   5  
The keyword auto has been given a new behavior since the C++11 Standard was ratified. Instantly I could appreciate the value of its new function when I considered things like declaring an iterator for a container. However, I was skeptical of any value that auto could provide for general purpose use.

The keyword auto has been given a new behavior since the C++11 Standard was ratified. Instantly I could appreciate the value of its new function when I considered things like declaring an iterator for a container. However, I was skeptical of any value that auto could provide for general purpose use.

Now that I have had a chance to study this new keyword I believe that it is quite a valuable addition to Modern C++. While there are situations that could still cause some grief, they are not difficult to detect, and the solutions to the problem are straight-forward to apply

Basic Usage

Here are a few examples for reference that will give context to this discussion. auto has been repurposed to allow developers to take advantage of the type information known to the compiler. This provides the potential benefit to make code easier to read and write.

I have added a comment that shows the type that each auto variable will be assigned. This is also the same declaration that would be required if auto were not used.

C++

std<span style="color: #008080;">::</span><span style="color: #007788;">map</span><span style="color: #000080;"><</span><span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">long</span>, std<span style="color: #008080;">::</span><span style="color: #007788;">string</span><span style="color: #000080;">></span>    keys<span style="color: #008080;">;</span>
<span style="color: #0000ff;">auto</span> value <span style="color: #000080;">=</span> <span style="color: #0000dd;color: red">101</span><span style="color: #008080;">;</span>             <span style="color: #666666;font-weight: 100; color: #008000">// int</span>
<span style="color: #0000ff;">auto</span> other <span style="color: #000080;">=</span> 101ul<span style="color: #008080;">;</span>           <span style="color: #666666;font-weight: 100; color: #008000">// unsigned long</span>
 
<span style="color: #666666;font-weight: 100; color: #008000">// std::map<unsigned long, std::string>::iterator</span>
<span style="color: #0000ff;">auto</span>  iter <span style="color: #000080;">=</span> keys.<span style="color: #007788;">find</span><span style="color: #008000;color: black; font-style: bold">(</span>value<span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span>
 
<span style="color: #666666;font-weight: 100; color: #008000">// std::string</span>
<span style="color: #0000ff;">auto</span>  entry <span style="color: #000080;">=</span> iter <span style="color: #000040;">!</span><span style="color: #000080;">=</span> keys.<span style="color: #007788;">end</span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">)</span>
            <span style="color: #008080;">?</span> iter<span style="color: #000040;">-</span><span style="color: #000080;">></span>second
            <span style="color: #008080;">:</span> <span style="color: #FF0000;color: #A31515">""</span><span style="color: #008080;">;</span>
 
<span style="color: #666666;font-weight: 100; color: #008000">// std::string::size_type</span>
<span style="color: #0000ff;">auto</span> len <span style="color: #000080;">=</span> entry.<span style="color: #007788;">size</span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span>      <span style="color: #666666;font-weight: 100; color: #008000">// std::string::size_type</span>
<span style="color: #0000ff;font-style: bold;">if</span> <span style="color: #008000;color: black; font-style: bold">(</span>len <span style="color: #000080;">></span> <span style="color: #0000dd;color: red">0</span><span style="color: #008000;color: black; font-style: bold">)</span>
<span style="color: #008000;color: black; font-style: bold">{</span>
  <span style="color: #0000ff;">auto</span> first <span style="color: #000080;">=</span> entry<span style="color: #008000;color: black; font-style: bold">[</span><span style="color: #0000dd;color: red">0</span><span style="color: #008000;color: black; font-style: bold">]</span><span style="color: #008080;">;</span>      <span style="color: #666666;font-weight: 100; color: #008000">// char</span>
  <span style="color: #0000ff;">auto</span> data <span style="color: #000080;">=</span> entry.<span style="color: #007788;">c_str</span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span>  <span style="color: #666666;font-weight: 100; color: #008000">// const char*</span>
  <span style="color: #0000ff;">auto</span> first_data <span style="color: #000080;">=</span> data<span style="color: #008000;color: black; font-style: bold">[</span><span style="color: #0000dd;color: red">0</span><span style="color: #008000;color: black; font-style: bold">]</span><span style="color: #008080;">;</span>  <span style="color: #666666;font-weight: 100; color: #008000">// char</span>
<span style="color: #008000;color: black; font-style: bold">}</span>

Initial Doubts

I am not the only programmer to have doubts about allowing the system to automatically choose the types of my variables. There are a number of questions asked around the web like this one from StackExchange and other sites.

There were two fundamental sources of my doubt.

Flashbacks of Visual Basic

I spent a brief moment of my career developing with Visual Basic. (Hey! I only did it to pay for tuition while I was in college. sigh).

To declare a new variable you would use the keyword Dim. If you hadn't defined a variable explicitly with Dim, then the compiler would give you an error. Variables that were not given an explicit type in Visual Basic used a type called Variant.

If you ever have programmed with Microsoft's COM, then you are aware that a Variant could be coerced into different types at run-time. BasicallyEssentially allowing this strongly-typed static language to bend the rules when using the Variant.

It did not take me long to realize that auto in Modern C++ is nothing like a Variant.

The chaos of using unknown types

This is only a misconceived notion. The type is well known by the compiler after it verifies the correctness of your code and before it generates any of the final object code. The syntax used in the declarations and statements have well-defined rules to determine these types. This is especially true for C++; any version of C++.

There are subtle coercion rules that have always existed to allow C code to be more compatible with the stronger type-checking that is present in C++. These rules mostly deal with the width of an integer or converting an object from one type to a compatible type without cluttering the syntax.

If you still have doubts, inspect the type of assigned to your variable within your IDE or debugger. There is a definitive type that has been deduced and assigned for every auto variable. This type is fixed and will not change.

Automatic type deduction

Are you familiar with templates and how the types are deduced for parametric variables? If so, then you know almost all there is to know about how the type is determined for auto variables. If you aren't familiar with all of the rules, it's OK, because the compiler is.

The rules are the same between the two forms of variable declaration with one exception, which is when a curly-braced initializer list is considered in the type deduction. In this case, the auto declared variable assumes the type to be an std::initializer_list that was also added to Modern C++. A template-deduced type in this situation requires you to explicitly specify the std::initializer_list type. The type T contained within the std::initializer_list<T> will then be deduced by the template.

I also want to remind you about the existence of Type Decay[^], it seems probable to me that you will encounter this at some point using auto. This coercion rule applies to both template and auto type deduction.

C++ 14

C++14 has added the possibility for auto to be used as the return type for a function.

C++

<span style="color: #666666;font-weight: 100; color: #008000">// Let's wrap the map lookup code </span>
<span style="color: #666666;font-weight: 100; color: #008000">// from above into a convenient function.</span>
<span style="color: #666666;font-weight: 100; color: #008000">// The return type will be a std::string.</span>
<span style="color: #0000ff;">auto</span> createName<span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #0000ff;">unsigned</span> index<span style="color: #008000;color: black; font-style: bold">)</span>
<span style="color: #008000;color: black; font-style: bold">{</span>
  <span style="color: #0000ff;">auto</span>  iter <span style="color: #000080;">=</span> keys.<span style="color: #007788;">find</span><span style="color: #008000;color: black; font-style: bold">(</span>value<span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span>
 
  <span style="color: #0000ff;font-style: bold;">return</span> iter <span style="color: #000040;">!</span><span style="color: #000080;">=</span> keys.<span style="color: #007788;">end</span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">)</span>
         <span style="color: #008080;">?</span> iter<span style="color: #000040;">-</span><span style="color: #000080;">></span>second
         <span style="color: #008080;">:</span> <span style="color: #FF0000;color: #A31515">""</span><span style="color: #008080;">;</span>
<span style="color: #008000;color: black; font-style: bold">}</span>

It is important to note, that every return point from the function must result with the same return type, which also allows the possibility for type conversion of the values into the same type. This is more evidence that demonstrates there is nothing magical about auto. The final code that it generates follows the same rules as if you had explicitly defined the values yourself.

There is a catch

The auto type must use the rules for template type-deduction. This means that it is not possible to use auto when you would like to return a std::initializer_list.

C++

<span style="color: #666666;font-weight: 100; color: #008000">// auto return types use the same</span>
<span style="color: #666666;font-weight: 100; color: #008000">// type deduction rules as templates.</span>
<span style="color: #0000ff;">auto</span> Fibonacci_5<span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">)</span>
<span style="color: #008000;color: black; font-style: bold">{</span>
  <span style="color: #666666;font-weight: 100; color: #008000">// This type of use is not legal.</span>
  <span style="color: #0000ff;font-style: bold;">return</span> <span style="color: #008000;color: black; font-style: bold">{</span><span style="color: #0000dd;color: red">1</span>,<span style="color: #0000dd;color: red">1</span>,<span style="color: #0000dd;color: red">2</span>,<span style="color: #0000dd;color: red">3</span>,<span style="color: #0000dd;color: red">5</span><span style="color: #008000;color: black; font-style: bold">}</span><span style="color: #008080;">;</span>
<span style="color: #008000;color: black; font-style: bold">}</span>

This rule also applies to the type deduction for the evaluation of lambda expressions.

C++

<span style="color: #666666;font-weight: 100; color: #008000">// This version cannot be deduced by the </span>
<span style="color: #666666;font-weight: 100; color: #008000">// compiler and results in an error.</span>
std<span style="color: #008080;">::</span><span style="color: #007788;">vector</span><span style="color: #000080;"><</span><span style="color: #0000ff;">int</span><span style="color: #000080;">></span> numbers<span style="color: #008080;">;</span>
<span style="color: #0000ff;">auto</span> initSequence <span style="color: #000080;">=</span>
  <span style="color: #008000;color: black; font-style: bold">[</span><span style="color: #000040;">&</span>numbers<span style="color: #008000;color: black; font-style: bold">]</span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">auto</span><span style="color: #000040;">&</span> sequence<span style="color: #008000;color: black; font-style: bold">)</span>
  <span style="color: #008000;color: black; font-style: bold">{</span>
    numbers <span style="color: #000080;">=</span> sequence<span style="color: #008080;">;</span>
  <span style="color: #008000;color: black; font-style: bold">}</span><span style="color: #008080;">;</span>
 
initSequence<span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">{</span><span style="color: #0000dd;color: red">1</span>,<span style="color: #0000dd;color: red">1</span>,<span style="color: #0000dd;color: red">2</span>,<span style="color: #0000dd;color: red">3</span>,<span style="color: #0000dd;color: red">5</span><span style="color: #008000;color: black; font-style: bold">}</span><span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span>

To make this expression valid, the same adjustment required for templates is required. The std::initializer_list&lt;T> needs to be specified, then the type T can be deduced.

C++

<span style="color: #666666;font-weight: 100; color: #008000">// The initializer_list is explicitly specified</span>
<span style="color: #666666;font-weight: 100; color: #008000">// to make this lambda expression legal.</span>
std<span style="color: #008080;">::</span><span style="color: #007788;">vector</span><span style="color: #000080;"><</span><span style="color: #0000ff;">int</span><span style="color: #000080;">></span> numbers<span style="color: #008080;">;</span>
<span style="color: #0000ff;">auto</span> initSequence <span style="color: #000080;">=</span>
  <span style="color: #008000;color: black; font-style: bold">[</span><span style="color: #000040;">&</span>numbers<span style="color: #008000;color: black; font-style: bold">]</span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">initializer_list</span><span style="color: #000080;"><</span><span style="color: #0000ff;">auto</span><span style="color: #000080;">></span><span style="color: #000040;">&</span> sequence<span style="color: #008000;color: black; font-style: bold">)</span>
  <span style="color: #008000;color: black; font-style: bold">{</span>
    numbers <span style="color: #000080;">=</span> sequence<span style="color: #008080;">;</span>
  <span style="color: #008000;color: black; font-style: bold">}</span><span style="color: #008080;">;</span>

Advantages

The advantages of auto are immediately apparent when you consider the amount of clutter that is removed when you use iterators or a moderately complicated template statement.

C++

<span style="color: #666666;font-weight: 100; color: #008000">// Something like this:</span>
std<span style="color: #008080;">::</span><span style="color: #007788;">shared_ptr</span><span style="color: #000080;"><</span>std<span style="color: #008080;">::</span><span style="color: #007788;">vector</span><span style="color: #000080;"><</span>std<span style="color: #008080;">::</span><span style="color: #007788;">pair</span><span style="color: #000080;"><</span>T, U<span style="color: #000080;">>>></span> sp_values
  <span style="color: #000080;">=</span> std<span style="color: #008080;">::</span><span style="color: #007788;">make_shared</span><span style="color: #000080;"><</span>std<span style="color: #008080;">::</span><span style="color: #007788;">vector</span><span style="color: #000080;"><</span>std<span style="color: #008080;">::</span><span style="color: #007788;">pair</span><span style="color: #000080;"><</span>T, U<span style="color: #000080;">>>></span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span>
  ...
<span style="color: #007788;">std</span><span style="color: #008080;">::</span><span style="color: #007788;">vector</span><span style="color: #000080;"><</span>std<span style="color: #008080;">::</span><span style="color: #007788;">pair</span><span style="color: #000080;"><</span>T, U<span style="color: #000080;">>></span><span style="color: #008080;">::</span><span style="color: #007788;">iterator</span> iter
  <span style="color: #000080;">=</span> std<span style="color: #008080;">::</span><span style="color: #007788;">find</span><span style="color: #008000;color: black; font-style: bold">(</span>sp_values.<span style="color: #007788;">begin</span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">)</span>, sp_values.<span style="color: #007788;">end</span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">)</span>, <span style="color: #0000dd;color: red">100</span><span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span>
 
<span style="color: #666666;font-weight: 100; color: #008000">// becomes:</span>
<span style="color: #0000ff;">auto</span> sp_values <span style="color: #000080;">=</span> std<span style="color: #008080;">::</span><span style="color: #007788;">make_shared</span><span style="color: #000080;"><</span>std<span style="color: #008080;">::</span><span style="color: #007788;">vector</span><span style="color: #000080;"><</span>std<span style="color: #008080;">::</span><span style="color: #007788;">pair</span><span style="color: #000080;"><</span>T, U<span style="color: #000080;">>>></span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span>
<span style="color: #0000ff;">auto</span> iter      <span style="color: #000080;">=</span> std<span style="color: #008080;">::</span><span style="color: #007788;">find</span><span style="color: #008000;color: black; font-style: bold">(</span>sp_values.<span style="color: #007788;">begin</span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">)</span>, sp_values.<span style="color: #007788;">end</span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">)</span>, <span style="color: #0000dd;color: red">100</span><span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span>

However, there are other advantages that are not immediately obvious.

Less typing (explicitly and with your keyboard)

Yeah, this is the low hanging fruit. I should mention, there is one exception, and that is if the type you need is an int. I also suppose there exists sadistic programmers that typedef or alias, one and two character length type names; so that would be another exception.

Along the same theme of less typing is refactoring data-fields. Changing types or function signatures. If you use auto effectively, you may only need to update the declaration in the header file and the functions definition to complete your refactor.

auto defined variables will be initialized

When a variable is defined with auto, it must be assigned an initial value. Otherwise there would be no way to determine its type:

C++

<span style="color: #0000ff;">auto</span> count<span style="color: #008080;">;</span>      <span style="color: #666666;font-weight: 100; color: #008000">// This is illegal, must be initialized</span>
 
<span style="color: #0000ff;">auto</span> value <span style="color: #000080;">=</span> <span style="color: #0000dd;color: red">10</span><span style="color: #008080;">;</span> <span style="color: #666666;font-weight: 100; color: #008000">// OK, assigned type int</span>

One thing that I try to teach developers that I mentor, is to not define the variable until you need it. Many developers still seem to forward declare all of their variables at the top of a function. That isn't necessary. Furthermore, objects with constructors may not be cheap, and if you drop out of the function before you use the constructed object, well that's just wasteful.

I think declaring your variables at the point they become necessary using auto will help advance this style.

Portability

This next set of declarations is a common occurrence, where the programmer explicitly selected the type for the variable, and they almost got it right, or maybe not at all. Selecting the incorrect type may be the difference between correct behavior and a security vulnerability. Another consequence that is less severe, depending on who you ask, would be truncation, or data loss.

C++

<span style="color: #666666;font-weight: 100; color: #008000">// No, std::size_t</span>
<span style="color: #0000ff;">int</span> len <span style="color: #000080;">=</span> <span style="color: #008080;">::</span><span style="color: #0000dd;">strlen</span><span style="color: #008000;color: black; font-style: bold">(</span>buffer<span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span>
 
<span style="color: #666666;font-weight: 100; color: #008000">// Maybe, if you're on a 32-bit system.</span>
<span style="color: #666666;font-weight: 100; color: #008000">// Narrowing truncation is possible on a 64-bit system.</span>
<span style="color: #666666;font-weight: 100; color: #008000">// std::size_type, which is generally defined as </span>
<span style="color: #666666;font-weight: 100; color: #008000">// std::size_t</span>
std<span style="color: #008080;">::</span><span style="color: #007788;">string</span> name <span style="color: #000080;">=</span> <span style="color: #FF0000;color: #A31515">"Code of the Damned"</span><span style="color: #008080;">;</span>
<span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">long</span> size <span style="color: #000080;">=</span> name.<span style="color: #007788;">size</span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span>
 
<span style="color: #666666;font-weight: 100; color: #008000">// No not even close, are you even trying?</span>
<span style="color: #666666;font-weight: 100; color: #008000">// Of course I'll still accept it...</span>
<span style="color: #0000ff;">double</span> how_big <span style="color: #000080;">=</span> <span style="color: #008080;">::</span><span style="color: #0000dd;">strlen</span><span style="color: #008000;color: black; font-style: bold">(</span>buffer<span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span>

It seems that I am always correcting warnings such as thiswarning: '<' : signed/unsigned mismatch. While learning secure coding practices I adopted the habit of using unsigned types for values that will be used as an index to reference memory. In fact, std::size_t has become my defacto unsigned type. It is guaranteed to be large enough to reference the largest address on the system.

As it turns out, it's not always possible, or even correct for an unsigned type to be used in comparison operations. Then I am left with a cast of some sort. auto solves this problem by selecting a compatible type with your initialization value. The most frequent place this seems to occur is within for loops:

C++

<span style="color: #666666;font-weight: 100; color: #008000">// Yes, 'i' is signed and size() returns an unsigned value</span>
<span style="color: #0000ff;font-style: bold;">for</span> <span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #0000ff;">int</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;color: red">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;"><</span> name.<span style="color: #007788;">size</span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;color: black; font-style: bold">)</span>
<span style="color: #008000;color: black; font-style: bold">{</span> ... <span style="color: #008000;color: black; font-style: bold">}</span>
 
<span style="color: #666666;font-weight: 100; color: #008000">// auto doesn't fix things alone.</span>
<span style="color: #666666;font-weight: 100; color: #008000">// However, adding a type-specifier to 0 helps.</span>
<span style="color: #0000ff;font-style: bold;">for</span> <span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #0000ff;">auto</span> i <span style="color: #000080;">=</span> 0ul<span style="color: #008080;">;</span> i <span style="color: #000080;"><</span> name.<span style="color: #007788;">size</span><span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;color: black; font-style: bold">)</span>
<span style="color: #008000;color: black; font-style: bold">{</span> ... <span style="color: #008000;color: black; font-style: bold">}</span>
 
<span style="color: #666666;font-weight: 100; color: #008000">// This is Modern C++.</span>
<span style="color: #666666;font-weight: 100; color: #008000">// Use a range-based for loop and be done with it.</span>
<span style="color: #0000ff;font-style: bold;">for</span> <span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #0000ff;">auto</span> i <span style="color: #008080;">:</span> name<span style="color: #008000;color: black; font-style: bold">)</span>
<span style="color: #008000;color: black; font-style: bold">{</span> ... <span style="color: #008000;color: black; font-style: bold">}</span>

Efficiency

That is correct. Consider all of the coercion and transformation techniques that may be used by the compiler to allow your program to compile successfully and run efficiently. Techniques such as move-semantics, const-correctness, temporary copies, the list goes on.

I have already argued that we don't always succeed in selecting the correct type just to hold the size of a container. Selecting the best type for efficiency is an even more difficult decision. The most probable place an incorrectly selected type could affect performance is within a loop. However, another time to consider replacing your type declaration to auto is when you are running a profiler trying to optimize your code, and you identify a hot-spot that seems to be making unnecessary copies. Using an auto declaration may give the compiler the freedom it needs to select a more efficient type and eliminate those copies.


Be aware of proxy classes

Yes, there is another potential gotcha that is important to know exists. Proxy classes are useful in variety of ways. The list below is not exhaustive, and it is likely the proxy class exists for more than one reason found on the list:

  • Transparently provide remote access
  • Delay expensive calculations until required
  • Encapsulate logic for efficiency
  • Protect direct access to encapsulated data
  • Formulate expression templates

Libraries commonly use proxy classes to simplify the syntax required to interface with the library objects. Expression templates a very common with math-based libraries to retain the natural mathematic syntax that is possible in C++. A Matrix class for example, or even a multi-dimensional array.

Example: Alchemy Proxies

I use proxy[^] classes in Alchemy to make the data fields of a message appear to the caller to be a fundamental type that is part of a struct. Each field is contained within its own proxy object, which knows how to efficiently manage the different operations supported in Alchemy.

Each proxy class contains a type-conversion function to extract the actual value from the proxy object. Here is an example definition of a 3-dimensional point.

C++

<span style="color: #666666;font-weight: 100; color: #008000">// Define an Alchemy message structure</span>
<span style="color: #666666;font-weight: 100; color: #008000">// to represent a 3-d point.</span>
ALCHEMY_STRUCT<span style="color: #008000;color: black; font-style: bold">(</span>pt3d_t,
  ALCHEMY_DATUM <span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #0000ff;">double</span>, X<span style="color: #008000;color: black; font-style: bold">)</span>,
  ALCHEMY_DATUM <span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #0000ff;">double</span>, Y<span style="color: #008000;color: black; font-style: bold">)</span>,
  ALCHEMY_DATUM <span style="color: #008000;color: black; font-style: bold">(</span><span style="color: #0000ff;">double</span>, Z<span style="color: #008000;color: black; font-style: bold">)</span>
<span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span>
 
<span style="color: #666666;font-weight: 100; color: #008000">// Create an initialized instance of the message with:</span>
<span style="color: #666666;font-weight: 100; color: #008000">// X=1.0, Y=2.0, Z=3.0</span>
Hg<span style="color: #008080;">::</span><span style="color: #007788;">basic_msg</span><span style="color: #000080;"><</span>pt3d_t<span style="color: #000080;">></span>  pt_msg <span style="color: #000080;">=</span> <span style="color: #008000;color: black; font-style: bold">{</span><span style="color:#800080;">1.0</span>, <span style="color:#800080;">2.0</span>, <span style="color:#800080;">3.0</span><span style="color: #008000;color: black; font-style: bold">}</span><span style="color: #008080;">;</span>

A comparison of the results between explicit type declaration and auto type declaration.

C++

<span style="color: #666666;font-weight: 100; color: #008000">// x_val is assigned 1.0</span>
<span style="color: #0000ff;">double</span> x_val <span style="color: #000080;">=</span> pt_msg.<span style="color: #007788;">X</span><span style="color: #008080;">;</span>
 
<span style="color: #666666;font-weight: 100; color: #008000">// ax_val is given the type:</span>
<span style="color: #666666;font-weight: 100; color: #008000">// Hg::detail::DataProxy</span>
<span style="color: #666666;font-weight: 100; color: #008000">//   < Hg::fundamental_trait, 0, Hg::TypeList<double, double, double>></span>
<span style="color: #0000ff;">auto</span> ax_val <span style="color: #000080;">=</span> pt_msg.<span style="color: #007788;">X</span><span style="color: #008080;">;</span>

Clearly, ax_val is not assigned the type double, as would be desired in most circumstances. That is because the compiler actually does get the same type for the auto declared variable to the explicitly declared double x_val.

If that were the end, the result would be a compiler error. However, the proxy class implements a type-conversion function, operator value_type() const, where this is the definition for value_type, typedef double value_type; Now the compiler has the leeway to coerce the proxy object into the declared type, double, and the statement becomes valid.

Another name for proxy classes that have conversion operators like this, are also referred to as, invisible proxies.

What is the solution?

First, recognize that auto is doing exactly what it is supposed to do in this case. Then we can admit that it does not actually arrive at the desired type, a double.

Item 6 from, Scott Meyer's, Effective Modern C++ offers a solution that he calls the explicitly typed initializer idiom. The solution is to explicitly specify the desired type with a static_cast.

C++

<span style="color: #666666;font-weight: 100; color: #008000">// ax_val is now a double and will be assigned the value 1.0</span>
<span style="color: #0000ff;">auto</span> ax_val <span style="color: #000080;">=</span> <span style="color: #0000ff;">static_cast</span><span style="color: #000080;"><</span><span style="color: #0000ff;">double</span><span style="color: #000080;">></span><span style="color: #008000;color: black; font-style: bold">(</span>pt_msg.<span style="color: #007788;">X</span><span style="color: #008000;color: black; font-style: bold">)</span><span style="color: #008080;">;</span>

This scenario is most likely to occur when the library you are using allows for a terse and expressive syntax. When you suspect auto is not assigning the type that you expected, take a look at the definition of the class that owns the expression. If the return type is a proxy object you can either explicitly cast to the desired type, or revert to the classic form of type declaration.


Summary

auto has been re-purposed in Modern C++. A cursory glance of the change reveals some benefits. However, the benefits run much deeper than the novelty applications that you can imagine. Adopting a consistent use of auto to declare your variable types will most likely improve your codes correctness, portability, efficiency, and most of all readability. If you have previously considered auto, and decided that it wasn't for you, take a moment to reconsider. auto has great potential.

This article was originally posted at http://codeofthedamned.com/index.php/c-auto

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer
United States United States
I am a software architect and I have been developing software for nearly two decades. Over the years I have learned to value maintainable solutions first. This has allowed me to adapt my projects to meet the challenges that inevitably appear during development. I use the most beneficial short-term achievements to drive the software I develop towards a long-term vision.

C++ is my strongest language. However, I have also used x86 ASM, ARM ASM, C, C#, JAVA, Python, and JavaScript to solve programming problems. I have worked in a variety of industries throughout my career, which include:
• Manufacturing
• Consumer Products
• Virtualization
• Computer Infrastructure Management
• DoD Contracting

My experience spans these hardware types and operating systems:
• Desktop
o Windows (Full-stack: GUI, Application, Service, Kernel Driver)
o Linux (Application, Daemon)
• Mobile Devices
o Windows CE / Windows Phone
o Linux
• Embedded Devices
o VxWorks (RTOS)
o Greenhills Linux
o Embedded Windows XP

I am a Mentor and frequent contributor to CodeProject.com with tutorial articles that teach others about the inner workings of the Windows APIs.

I am the creator of an open source project on GitHub called Alchemy[^], which is an open-source compile-time data serialization library.

I maintain my own repository and blog at CodeOfTheDamned.com/[^], because code maintenance does not have to be a living hell.

Comments and Discussions

 
-- There are no messages in this forum --