Concepts / Creating Tuples with make_tuple

Creating Tuples with make_tuple

Tuple elements are numbered starting from zero, unlike pair elements that are named first and second.

  • Programming

A Tuple With Three Slots

A tuple groups several values into a single object. The source builds one from a string, an int, and a double, using make_tuple so that the types are deduced from the values you pass in. Once the tuple exists, each of its values can be read back out, but the way you name a value matters a great deal. Before reading on, try the question below.

What do you think happens?

A tuple t is made with a string, an int, and a double, in that order. What does get<1>(t) return?

  • The string, because it is the first value

  • The int, because counting starts at zero and index 1 is the second element

  • The double, because it is the last value

Reveal answer
Answer:

The int, because counting starts at zero and index 1 is the second element

Tuple elements are numbered from zero. The first element is at index 0, so index 1 is the second element, which here is the int. Thinking of index 1 as the first value is the most common early mistake.

Tracing the Positions of a Tuple

Every value in a tuple sits in a numbered position. The diagram below shows the same tuple the source uses: a string, an int, and a double, created with make_tuple. Each position holds one value and has one number. Reading the diagram from left to right gives the order of the elements, and the number under each box is the number you pass to get.

string valueindex 0int valueindex 1double valueindex 2
Which value sits at index 0, index 1, and index 2 in a tuple built with make_tuple, and why counting starts at zero?
Worked example

Reading the three positions

A tuple t holds a string, an int, and a double, in that order. Which value does each of get<0>(t), get<1>(t), and get<2>(t) read?

  1. 1
    Count the position from zero

    The first element is at index 0. Start counting at zero, not one, when you look at the position number.

  2. 2
    Match index 0 to the first value

    Index 0 is the string, the first element in the tuple's order.

  3. 3
    Match index 1 to the second value

    Index 1 is the int. Moving one position to the right from the string gives the int.

  4. 4
    Match index 2 to the third value

    Index 2 is the double, the third and last element.

Result

get<0>(t) reads the string, get<1>(t) reads the int, and get<2>(t) reads the double.

How make_tuple Fills the Slots

make_tuple takes the values you pass it as arguments and places them into the tuple's slots. The order of the arguments determines the order of the slots, and that order is what fixes each element's index. The first argument ends up in the slot numbered zero, the second in the slot numbered one, and so on. The diagram shows that flow for three arguments.

hellofirst argumentmake_tupletuple tindex 0, 1, 242second argument3.5third argumentindex 0index 1index 2creates
How the values passed to make_tuple flow into the tuple, and how their order decides which index each value gets.

Why Counting Starts at Zero

The elements of a tuple are numbered starting from zero. This differs from a pair, whose elements are named first and second. A tuple has no names for its elements, so position is the only handle you have. The first element is at index 0, the second at index 1, and the third at index 2. Counting from zero is the rule for every tuple index, which means the first element is never reached with index 1.

Definition

A tuple index is the position number of an element inside a tuple. Positions are counted from zero, so the first element has index 0.

FeaturePairTuple
How elements are reachedBy the names first and secondBy position number, starting from zero
Names for elementsYes, first and secondNone, so position is the only handle
Index of the first elementNot a number; use first0

Pair elements have names, while tuple elements are reached only by their numbered position.

Retrieving an Element with get

A tuple element is accessed with get<index>(tuple). The index is written inside the angle brackets and the tuple is passed as the argument. The source gives three examples that read the first, second, and third elements of the same tuple. The program below follows that pattern. Trace it line by line, then check the output.

helloindex 042returned by get<1>(t)42index 13.5index 2get<1>(t)
When get<1>(t) is called, which stored element is returned, and how does the index position map to that element?
Code walkthrough
#include <iostream>
#include <string>
#include <tuple>

int main() {
    auto t = std::make_tuple(std::string("hello"), 42, 3.5);
    std::cout << std::get<0>(t) << "\n";
    std::cout << std::get<1>(t) << "\n";
    std::cout << std::get<2>(t) << "\n";
    return 0;
}
  1. 1
    Line 6 creates the tuple t. The first argument becomes index 0, the second index 1, and the third index 2.
  2. 2
    Line 7 calls get<0>(t). The index 0 selects the first element, so hello is printed.
  3. 3
    Line 8 calls get<1>(t). The index 1 selects the second element, so 42 is printed, not hello.
  4. 4
    Line 9 calls get<2>(t). The index 2 selects the third element, so 3.5 is printed.
  • make_tuple builds the tuple with a string, an int, and a double, in that order
  • get<0>(t) reads the element at index 0, the string
  • get<1>(t) reads the element at index 1, the int
  • get<2>(t) reads the element at index 2, the double
Output
hello
42
3.5

Choosing the Access Form

A common first guess is that a tuple's elements can be reached the way any other collection is, by writing the tuple's name followed by a number in square brackets, or by calling a generic function with the tuple and a number as arguments. The source names both of these guesses as misconceptions. Its position is that elements are reached with get<index>(tuple), and that get(t,1) and t[1] are not the way to access tuple elements for this purpose.

Access formStatus in this materialReason given
get<index>(tuple)The form to useThe index is part of the code itself, so the element is selected at compile time
get(t,1)Named as a misconceptionNot the way to select a tuple element at compile time
t[1]Named as a misconceptionNot the way to select a tuple element at compile time

The source's choice of access form for selecting a tuple element.

The index in get<index> is written into the code and is not computed while the program runs. That is what the source means by compile-time selection: the position of the element you want is fixed when the program is compiled. The source is candid that this form is not elegant, calling it ugly, but it is the form it teaches because it is the way to get compile-time selection of an element.

Mistakes When Reading Tuple Positions

  • Common mistake

    Expecting get<1> to return the first element

    What it looks like

    With t made from hello, 42, and 3.5, reading get<1>(t) and expecting hello

    Why it fails

    Positions are numbered from zero, so index 1 is the second element, which is 42.

    Do this instead

    Count from zero: index 0 is hello, index 1 is 42, and index 2 is 3.5.

  • Common mistake

    Using t[1] because other collections work that way

    What it looks like

    Writing t[1] to read the second element of a tuple

    Why it fails

    The source names t[1] as a misconception for accessing tuple elements.

    Do this instead

    Write get<1>(t) to read the element at index 1.

  • Common mistake

    Using get(t,1) with a number in parentheses

    What it looks like

    Writing get(t,1) to select the element at index 1

    Why it fails

    The source names get(t,1) as a misconception and does not use it for compile-time selection.

    Do this instead

    Write get<1>(t), with the index inside the angle brackets.

  • Common mistake

    Treating a tuple's position numbers as if they started at one, which shifts every value by one place

Tracing a Tuple Program

MEDIUM

Read the program below. Before running it, predict what each of the three lines prints, then compare your predictions with the expected output. Identify the line where a reader who counts from one would expect a different value than the program actually prints.

Hints
  • Start by writing down the index of each element: 0 for alpha, 1 for 10, and 2 for 2.5.
  • Then check which index each get call uses, and match it to the element at that index.
  • The unexpected result is the line whose index points to a value you did not expect when counting from one.
cpp
Output
10
alpha
2.5
Notes on the code
  • The first printed line uses get<1>, which reads the second element
  • The second printed line uses get<0>, which reads the first element
  • The third printed line uses get<2>, which reads the third element

Key Takeaways

  • Tuple elements are numbered starting from zero, so the first element is at index 0 and is never reached with index 1.
  • A tuple has no names for its elements, which is different from a pair whose elements are named first and second; position is the only handle.
  • make_tuple places its arguments into the tuple in order, and that order fixes each element's index.
  • Elements are retrieved with get<index>(tuple), where the index is part of the code and selected at compile time; get(t,1) and t[1] are named misconceptions for this purpose.
  • When tracing a tuple access, first count the position from zero, then match the value at that position to find an unexpected result.

More concepts starting with C