GotW #92: Auto Variables, Part 1

What does auto do on variable declarations, exactly? And how should we think about auto? In this GotW, we’ll start taking a look at C++’s oldest new feature.



JG Questions

1. What is the oldest C++11 feature? Explain.

2. What does auto mean when declaring a local variable?

Guru Questions

3. In the following code, what is the type of variables a through k, and why? Explain.

int         val = 0;
auto a = val;
auto& b = val;
const auto c = val;
const auto& d = val;

int& ir = val;
auto e = ir;

int* ip = &val;
auto f = ip;

const int ci = val;
auto g = ci;

const int& cir = val;
auto h = cir;

const int* cip = &val;
auto i = cip;

int* const ipc = &val;
auto j = ipc;

const int* const cipc = &val;
auto k = cipc;

4. In the following code, what type does auto deduce for variables a and b, and why? Explain.

int val = 0;

auto a { val };
auto b = { val };

22 thoughts on “GotW #92: Auto Variables, Part 1

  1. I wonder will the keyword auto be the new bugbear? Making code hard to understand completely without knowing the whole code base and the behavior of the compiler used.

    Will auto make it easier for programmers to make mistakes?

    Does anyone have any statistics on this yet?

  2. @GregM, in C++03 you’d want to use a type trait to isolate the container-specific type information and leave the main algorithm generic. But indeed decltype and auto make this much much more convenient.

  3. Ben, that’s a great example of how auto enables you to write much more generic code. Without auto, or at least decltype, which doesn’t provide any additional information beyond auto, you would have to write that function for each possible T, or at least pass the T down into some other template type such as vector. The ability to write generic code, of course, does mean that you need to know the types used in the instantiation before the other types that are dependent on it can be determined.

  4. I am not as good as a good IDE, that’s why people like to use IDEs. It will do the work for you and know the type of ‘b’.

    I can take a guess, though. With the code you posted, there is not enough information to determine the type. This is because if the template type “T” is in a namespace then Koenig lookup dicates that the namespace is considered for a method named “begin” and that method’s return type is not shown in this code.

    Oh, I think I just figured out your point. Your point is that the IDE can’t know the type of “b” either because this is templated code. Why didn’t you just say that? :) Good point.

  5. @jlehrer: I assume you’re at least as smart as a good IDE. So what’s the inferred type of b in this code:

    template<typename T>
    void frob( const T& t )
        using std::begin;
        auto b = begin(t);
        // ...
  6. I think about auto in the same way as I think about TAD, decltype on the other hand…

  7. @DavidBraun, a good IDE should be able to tell you the type of the auto-declared variable, reducing the reader’s unnecessary work.

  8. I’m thrilled having the new “auto” semantic, which is wonderful when a type specification is verbose and complex, and essential when the type is ineffable. However, one thing that is illustrated here is that, except for ineffable types, there is always *some* trade-off being made. In many cases the trade-off is so overwhelmingly positive that the negatives are negligible, however real. The negatives are rooted in loss of visibility of type information.

    The examples in problem #3 illustrate the need for clear understanding of typing rules to retrieve information that auto makes less apparent. The more simple the type specification (e.g. a built-in or an ordinary class) the less is gained by using auto and the greater the proportionate significance of diminishment of type visibility. A chained use of auto reduces type visibility even more, necessitating a bit of detective work just to figure out what *it* is one is looking at, and consequently what one can do with “it”. If, as has been advocated, auto should be used pervasively, doesn’t this make *some* code less comprehensible and give unnecessary work to the reader? Isn’t there a cumulative cognitive drain imposed by pervasive “type indirection”?

  9. What is the oldest feature, by topic guess its auto, and probably the best and most welcomed feature ever after =.
    What does it mean, it means happy coders :)

    @Ralph think you are right about Bjarne Stroustroup. It’s always been the ‘missing’ elephant in the room for c++ compared to other languages, and c++ is the language that can really make best use of it.

  10. Nice one. It would be interesting to discuss also decltype(auto), which will be available in C++14

  11. auto is the oldest feature… Herb said something like “they” made bjarne take it out. :D

  12. 1. I believe I heard Bjarne Stroustroup say that the idea of making auto do type inferrence was around back in the late 80s or early 90s, but that AT&T didn’t like it, since it would be too radical.

    2. auto finds the type of an expression and removes top-level const, volatile and references.


    int         val = 0;
    auto        a   = val;
    auto&       b   = val;
    const auto  c   = val;
    const auto& d   = val;
    int&        ir  = val;
    auto        e   = ir;

    Up to here you can replace auto with int and get the correct types.

    int*        ip  = &val; 
    auto        f   = ip;

    In this case auto is inferred as int*.

    const int   ci  = val;
    auto        g   = ci;
    const int&  cir = val;
    auto        h   = cir;

    Again constness and the references will simply be removed and int remains.

    const int*  cip = &val;
    auto        i   = cip;

    Now this will be infered to const int *, since it’s a pointer to a constant int and not a constant pointer to a mutable int. The const is not on the top level and hence will remain.

    int* const  ipc = &val;
    auto        j   = ipc;

    The j variable will be int*.

    const int* const cipc = &val;
    auto             k    = cipc;

    Again this will be a const int *.


    int val = 0;
    auto a { val };
    auto b = { val };

    This one I’m not 100% sure about, but I believe that a will be an int and b will be an std::initializer_list.

  13. Humm the first question seems interesting, but where should I know from. My guess: concepts, since templates do not seem to “fit-in” with static type checking. Or maybe also lambdas if you go back to lambda calculus..

  14. 1. Type deduction, it’s been around since templates only now can it be use intuitively.

  15. Okay… here are my guesses:

    1. auto?

    2. auto declares a variable on the stack of type that is deduced by the compiler.

    a: int
    b: int&
    c: const int
    d: const int&
    e: int&
    f: int*
    g: int
    h: const int&
    i: const int*
    j: int*
    k: const int*

    a: int
    b: std::initializer_list

    Now to see if I’m right…

Comments are closed.