Skip to content

Expert · Modern C++: lambdas, C++17 and C++20 essentials · topic 31 of 42 · 25 min

auto, structured bindings and other C++17 conveniences

Explanation

auto lets the compiler deduce a variable's type from its initial value. Structured bindings (auto [a, b] = pair;) unpack pairs, tuples and structs into named variables. C++17 also added if and switch with an initialiser, [[nodiscard]], inline variables and constexpr if.

auto: let the compiler write long type names

Types in C++ can get long: std::map<std::string, std::vector<int>>::const_iterator. auto tells the compiler to deduce the type from the initialiser. The variable still has one fixed type; auto just saves typing and avoids mistakes.

cpp
std::map<std::string, std::vector<int>> marksBySubject;
auto it = marksBySubject.find("Maths");     // instead of the long iterator type
auto count = 0;                              // int
auto price = 99.5;                           // double
auto name = std::string("Asha");             // std::string ("Asha" alone would be const char*)
Use auto when the type is obvious from the right side or very long.
Careful: auto drops references and top-level const. auto x = v[0]; makes a COPY. To refer to the element, write auto& x = v[0]; and to read without copying, const auto& x = v[0];. In range-for loops over big objects, use const auto&.

Structured bindings

cpp
#include <map>
#include <string>
#include <tuple>

std::pair<std::string, int> topper() { return {"Meena", 98}; }

auto [name, score] = topper();                       // name = "Meena", score = 98

std::map<std::string, int> stock = {{"rice", 40}, {"dal", 25}};
for (const auto& [item, qty] : stock) {
    std::cout << item << ": " << qty << '\n';
}

struct Point { int x; int y; };
auto [x, y] = Point{3, 4};

auto [it, inserted] = stock.insert({"oil", 10});      // insert returns (iterator, bool)
if (!inserted) std::cout << "already there\n";
Structured bindings unpack pairs, tuples, std::array and structs with public members, in order.

if and switch with an initialiser

cpp
if (auto it = stock.find("rice"); it != stock.end()) {
    std::cout << "rice left: " << it->second << '\n';
}   // it is not visible here

switch (auto code = getStatus(); code) {
    case 200: break;
    default: std::cout << "error " << code << '\n';
}
The variable lives only inside the if/switch, which keeps the surrounding scope clean.
Think of it like this: An if with an initialiser is like a token you get at a bank counter for one transaction. You use it while being served, and it is taken back when you leave the counter. It does not clutter your pocket afterwards.

Other small C++17 features

  • [[nodiscard]] on a function makes the compiler warn if the caller ignores its return value: [[nodiscard]] bool save();.
  • inline variables let you define a constant or static member in a header: inline constexpr double GST = 0.18;.
  • Nested namespaces: namespace shop::billing { } instead of two nested blocks.
  • std::size(container) and std::data(container) work for arrays and containers alike.
  • Class template argument deduction: std::pair p{1, 2.5}; std::vector v{1, 2, 3}; without writing <int, double>.

constexpr if (if constexpr)

cpp
template <typename T>
std::string describe(const T& value) {
    if constexpr (std::is_integral_v<T>) {
        return "integer " + std::to_string(value);
    } else {
        return "something else";
    }
}
if constexpr is decided at compile time; the branch not taken is not even compiled for that T. Useful inside templates.
Tip: A good rule from many style guides: use auto when it makes the code clearer (long iterator types, make_unique results, lambdas) and write the type when it adds information the reader needs (for example long long totalPaise).

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

auto, structured bindings and other C++17 conveniences · 1/6

C++17 conveniences

C plus plus seventeen made everyday code much shorter. Let us see the most useful features.

Prefer a video by a teacher? Find free videos on “c++17 features structured bindings auto if initializer tutorial” on YouTube ↗

In real life: Reading results from a booking function

A bus booking function returns two things: whether the seat was booked and the PNR or an error code. Returning a struct and unpacking it with a structured binding makes the calling code read like a sentence.

cpp
#include <iostream>
#include <string>

struct BookingResult { bool ok; std::string pnr; };

BookingResult bookSeat(int seat) {
    if (seat > 40) return {false, ""};
    return {true, "BUS" + std::to_string(1000 + seat)};
}

int main() {
    if (auto [ok, pnr] = bookSeat(12); ok) {
        std::cout << "Booked, PNR " << pnr << '\n';   // Booked, PNR BUS1012
    } else {
        std::cout << "Seat not available\n";
    }
}
An if with initialiser plus a structured binding, both C++17.

Practice (0/4 done)

Task 1 · Question

auto x = 5 / 2; What is the type and value of x?

Task 2 · Question

std::vector<int> v = {1, 2, 3}; for (auto x : v) x *= 10; What is v afterwards?

Task 3 · Question

std::pair<int, std::string> p{7, "seven"}; auto [n, word] = p; What are n and word?

Task 4 · Practice

Write a function std::pair<int, int> minMax(const std::vector<int>& v) and use it with a structured binding. Then loop over a std::map<std::string, double> of item prices with const auto& [item, price] and print only items under Rs 100, using an if with initialiser to look up "tea" first.

Quick quiz

Question 1

1.auto s = "hello"; What is the type of s?

Question 2

2.What can structured bindings unpack?

Question 3

3.What does [[nodiscard]] do?

Question 4

4.Where is a variable declared in if (auto x = f(); x > 0) visible?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

auto s = "hello"; What is the type of s?

Answer: const char*

A string literal decays to const char*. Write std::string("hello") or use the "hello"s literal for std::string.

What can structured bindings unpack?

Answer: Pairs, tuples, std::array and structs with public members

They work with any tuple-like type and simple aggregates.

What does [[nodiscard]] do?

Answer: Asks the compiler to warn when the return value is ignored

It helps catch ignored error results.

Where is a variable declared in if (auto x = f(); x > 0) visible?

Answer: Only inside the if and its else

Its scope is the whole if statement, including else branches.

auto x = 10 / 4; What is x?Related

Answer: 2 (int)

10 / 4 is int division, giving 2, so auto makes x an int.

From Variables, types and constants

Which is a valid C++20 designated initialiser for struct P { int x; int y; };?Related

Answer: P p{.x = 1, .y = 2};

Designators use .name and must follow the declaration order.

From C++20 ranges, views and other C++20 essentials

When does the compiler choose which overload to call?Related

Answer: At compile time, from the argument types

Overload resolution happens while compiling, based on the arguments in each call.

From Overloading, default arguments and recursion

Which of these is a tuple?Related

Answer: (1, 2)

Round brackets with commas make a tuple. Square brackets make a list, and curly braces make a set.

From Tuples: fixed groups of values

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 2 more topics in “Modern C++: lambdas, C++17 and C++20 essentials” before its exam: std::optional, std::variant and std::string_view, C++20 ranges, views and other C++20 essentials.
  2. Module 8 exam: Modern C++ · 12 questions · 25 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Exceptions, concurrency and building projects with CMake. 42 topics left in the course before the final exam.

← Previous: Lambdas: small functions written in place