Uses of ‘auto’ in Modern C++

The auto keyword has been part of C++ since C++11, and its role has developed somewhat since then. This article intends to cover all the use cases of auto, including syntax that is new in the upcoming C++23 standard. The list of uses covered is:

  1. Type deduction for variable definitions
  2. References to other entities
  3. Deduction of a function’s return type
  4. Generic lambdas and functions
  5. Making a temporary copy of an entity

1. Type deduction for variable definitions

The auto keyword an be used instead of a type specifier in all cases where a definition is also an initialization. Use of a * indicates that we know we are initializing a pointer type:

auto i = 1;
auto *s{ "hello" };
auto p = std::make_unique<Class>("param1", "param2");

By the way, in cases where the RHS is an entity such as another variable (including the return value of a function) or a reference, a copy is made (according to the copy semantics of the entity itself).

2. References to other entities

The qualifiers const, & and && can be used with auto; use of them is independent of the type of the RHS.

const auto& ri = i;    // ri cannot be modified
auto&& r = 3 + 4;      // r is an r-value reference

To give the LHS the same qualifiers as the RHS, the curious-looking construct decltype(auto) can be used:

decltype(auto) rri{ ri };
rri = 2;                   // rri, ri and i have value 2

It is not always obvious which of auto& and decltype(auto) needs to be used; as a rule of thumb remember that decltype is more flexible:

auto& print = std::cout;
decltype(auto) newline = &std::endl<char, std::char_traits<char>>;

print << "Hello, world!" << newline;

3. Deduction of a function’s return type

It used to be necessary to use decltype() and trailing return type syntax to avoid specifying the return type of a function explicitly, but now plain auto can be used in the function declaration or definition. There is a caveat: such a function must specify the definition before use.

auto f() {
    return 42;
}

Another restriction is that all the return expressions of a function defined with auto as the return type must evaluate to the same type. Even decltype(auto) can be used as a return type in Modern C++, this preserves constant/reference qualifiers (should auto-deducing a complex reference return type be necessary, for example).

4. Generic lambdas and functions

Lambdas were covered in a previous mini-series, while generic functions no longer needing the template<> keyword are new to C++20:

void g(auto a, auto b) {
    std::cout << "a = " << a << "\nb = " << b << '\n';
}

No checks are made on the types of parameters declared with auto, if these types should be constrained then template<> should be used together with C++ concepts.

Parameter packs are also supported, for example:

void logv(std::string_view fmt, auto&&... params) {
    auto args = std::make_format_args(std::forward<decltype(params)>(params)...);
    std::cerr << std::vformat(fmt, args) << '\n';
}
// ...
    logv("Hello {0} {1}!", 2, 'U');

Output is: Hello 2 U! Note that use of decltype(params) is necessary to infer the type for std::forward.

5. Making a temporary copy of an entity

For the case where a parameter passed to a function must not be a reference (if it might be modified by the function call, for example), but the desired argument is a reference (such as container.front()) this entity can be simply wrapped as auto{ ... } in order to obtain a temporary. The only difference to defining a new variable using auto beforehand is that its lifetime is the scope of the function call; there is no need to create a sub-scope in the caller environment.

std::vector<std::string_view> vsv{ "apple", "banana", "apple", "pear", "banana", "pear", "apple" };
vsv.erase(std::remove(begin(vsv), end(vsv), auto{ vsv.front() }), end(vsv));
// vsv is now correctly { "banana", "pear", "banana", "pear" }

This usage may find uses in other applications too, removing constant or reference qualifiers when passing exotic objects to template functions.

I hope I haven’t missed any uses of auto; if you know of any others, or have another example to share, please leave a comment.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s