Back Original

How well do you know C++ auto type deduction?

One of the most iconic C++ features is the language’s ability to deduce types with the auto keyword. In this post, I’ll give a series of code snippits. Your job is to assess what will be deduced for v in each case. Determine for each:

  1. The deduced type
  2. If it is a value, an lvalue or rvalue reference, or a pointer
  3. Which CV qualifiers are applicable

Some of these may not even compile, so “this won’t work” is a totally valid answer.

Each section increases in difficulty. Good luck!

Basics

Basic assignments and deduction from constants and straightforward types.


int x;
auto v = x;
Answer

auto v = 5, w = 0.1;
Answer

int x;
auto v = &x;
Answer

auto v = { 1, 2, 3 };
Answer

Type: std::initializer_list<int>


int x[5];
auto v = x;
Answer

int foo(int x) {
    return x;
}
auto v = foo;
Answer

Exploring how references and CV-qualifiers are handled.


volatile const int x = 1;
auto v = x;
Answer

volatile const int x = 1;
auto v = &x;
Answer

Type: volatile const int*


int x;
int& y = x;
auto v = y;
Answer

int x;
auto& v = x;
Answer

int x[5];
auto& v = x;
Answer

int foo(const int x) {
    return x;
}
auto v = foo;
Answer

Advanced

Forwarding references, decltype(auto), inheritance, structured binding, and lambdas.


int x;
auto&& v = x;
Answer

auto x = [] () -> int { 
    return 1;
};
auto&& v = x();
Answer

int x;
auto y = [&] () -> int& { 
    return x;
};
auto&& v = y();
Answer

int x;
decltype(auto) v = (x);
Answer

struct Foo {};
auto&& v = Foo{};
Answer

struct Foo {};
decltype(auto) v = Foo{};
Answer

int x;
decltype(auto) v = std::move(x);
Answer

int foo(int x) {
    return x;
}
decltype(auto) v = foo;
Answer

int foo(int x) {
    return x;
}
decltype(auto) v = (foo);
Answer

class Base {
    public:
        auto foo() {
            return this;
        };
};

class Derived : public Base {
};

Derived d;
auto v = d.foo();
Answer

Oof

Abandon all hope, ye who attempt to deduce the types of lambda captures in expressions with decltype(auto) and symbols defined via structured binding.


int x;
[&] {
    decltype(auto) v = x;
}();
Answer

int x;
[&] {
    decltype(auto) v = (x);
}();
Answer

int x;
[=] {
    decltype(auto) v = x;
}();
Answer

int x;
[=] {
    decltype(auto) v = (x);
}();
Answer

int x;
[=] mutable {
    decltype(auto) v = (x);
}();
Answer

int x;
int& y = x;
[=] () {
    decltype(auto) v = y;
}();
Answer

std::pair x {1, 2.0};
auto [v, w] = x;
Answer

Type: std::tuple_element<0, std::pair<int, float> >::type& (but which presents as an int in basically every observable way)

You can check any of these by using this GodBolt link. Shoutout to this Stack Overflow thread which provided the code snippit to print human readable names for a variable.

Do you have any interesting examples to share? Reach out at sam@volatileint.dev and let me know! If you found this article interesting, consider subscribing to the newsletter to hear about new posts!