Start learning free

LESSON 259 OF 667 · PAIRS, SORTING & BUILT-INS

Pairs in C++: pair, first, second and Unpacking

Lesson Read the full explanation

TL ; DR:

A pair keeps two values together, like a movie's title and year. Read them with .first and .second, or unpack them into variables.


pair<string, int> movie = {"Frozen", 2013};   // a title and a year

cout << movie.first << endl;                  // Frozen

cout << movie.second << endl;                 // 2013

auto [title, year] = movie;                   // unpacking

cout << title << " " << year << endl;         // Frozen 2013


Full lesson:

Some values belong together. A movie has a title and a year. A point has an x and a y. C++ keeps two values like these in a pair.

  • pair<string, int> is a pair of a string and an int. The types go in the angle brackets, in order.
  • pair<string, int> movie = {"Frozen", 2013}; makes one. The values go in curly braces.
  • movie.first is the first value, "Frozen". movie.second is the second, 2013.

auto [title, year] = movie; unpacks the pair into two new variables. You have seen this before, in for (auto& [name, points] : scores).

A function can return a pair. Its return type is the pair's type, like pair<int, int>. Then return {a, b}; builds it.

cout << movie doesn't compile. Print movie.first and movie.second instead.


Your task

Rex the dog went for a long walk. pet holds his name and his age.

First, make splitTime return its pair: the whole hours and the minutes left.

Then unpack pet into name and age.

Last, call splitTime(135). Unpack its result into hours and mins.

The code already prints the three lines.

Expected output:

Rex
Rex is 4
Rex walked 2 h 15 min
STEP 1 OF 3
    Ctrl + Enter to check

    C++ · PAIRS, SORTING & BUILT-INS

    Tuples in C++, explained

    What a pair is

    Some values belong together: a pet has a name and an age, a point has an x and a y. A pair holds exactly two values in one variable. The two types go in angle brackets, in order, and the values go in curly braces:

    pair<string, int> pet = {"Rex", 4};
    cout << pet.first << endl;   // Rex
    cout << pet.second << endl;  // 4

    .first is the first value and .second is the second. They are members, not functions, so there are no parentheses. The two types can differ, as here, or be the same, as in pair<int, int>.

    Unpacking a pair

    Instead of writing pet.first and pet.second every time, you can give the two values their own names:

    auto [name, age] = pet;
    cout << name << " " << age << endl;   // Rex 4

    auto [name, age] creates two new variables. The names are matched to the pair's values in order: the first name gets first, the second gets second. The types come from the pair, so name is a string and age is an int. The same square-bracket form works in a range-based loop, as in for (auto& [name, points] : scores).

    Returning a pair from a function

    A function that has two results can return one pair. Its return type is the pair's type, and return {a, b}; builds the pair:

    pair<int, int> splitTime(int minutes) {
        return {minutes / 60, minutes % 60};
    }

    With 135 minutes, 135 / 60 is the whole hours, 2, and 135 % 60 is what is left, 15. The caller can unpack the result straight away: auto [hours, mins] = splitTime(135);.

    Pairs in other places

    Pairs show up all over C++. A vector<pair<string, int>> is a list of records like (name, age), and a loop over it can unpack every element at once with for (auto& [name, age] : pets). A map is a collection of pairs too: each entry has a key and a value, which are the first and the second of the entry. Once .first and .second feel natural, those loops read the same way.

    Gotchas

    • A pair can't be printed directly. cout << pet doesn't compile: the compiler reports that there is no operator<< for std::ostream and std::pair<std::string, int>. Print pet.first and pet.second instead.
    • Order matters. auto [age, name] = pet; compiles, but age would hold the string and name the number. Names follow the order of the pair's types.
    • Unpacking copies. auto [name, age] = pet; makes new variables holding copies of the values, so changing age later does not change pet.second. Each name can only be declared once in a scope.

    The exercise, step by step

    1. Make splitTime return its pair. Return the whole hours and the minutes left in curly braces.
    2. Unpack pet into name and age with auto and square brackets.
    3. Unpack the result of splitTime(135) into hours and mins. A returned pair unpacks just like a variable.

    The finished lesson code:

    class Solution {
    public:
        pair<int, int> splitTime(int minutes) {
            return {minutes / 60, minutes % 60};
        }
    
        void mainFunction() {
            pair<string, int> pet = {"Rex", 4};
            cout << pet.first << endl;
    
            auto [name, age] = pet;
            cout << name << " is " << age << endl;
    
            auto [hours, mins] = splitTime(135);
            cout << name << " walked " << hours << " h " << mins << " min" << endl;
        }
    };

    It prints:

    Rex
    Rex is 4
    Rex walked 2 h 15 min

    Why not just two variables?

    Two separate variables work fine inside one function, but a pair travels as one value. A function can return it, a vector can hold many of them, and the two parts can never get out of step, such as a name that ends up with the wrong age.

    Key takeaways

    • pair<A, B> p = {x, y}; keeps two values together; read them with p.first and p.second.
    • auto [a, b] = p; unpacks a pair into two new variables, in order.
    • A function returns two results as a pair with return {x, y};.
    • Print the two parts separately; cout doesn't know how to print a whole pair.
    Keep going with C++500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free