Concepts / Type Deduction for Tuples

Type Deduction for Tuples

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

  • Programming

Predicting a Tuple Element Before Reading On

A tuple holds several values together, and it is often created so that the compiler works out the type of each value for you. Before you learn how to read one of those values back out, it helps to try a small prediction. Imagine a tuple that holds a string, an int and a double, created with make_tuple. Someone then asks for one of its elements using a numbered index. Which value would you expect to come back? Keep your guess in mind, because the rest of this article shows how positions in a tuple work.

What do you think happens?

Given a tuple t holding a string, an int and a double in that order, what does get<1>(t) return?

  • The string, because it is the first thing in the tuple

  • The int, because counting from zero makes index 1 the second element

  • The double, because it is the last element

Reveal answer
Answer:

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

Tuple positions are numbered from zero, so the first element is at index 0, the second at index 1 and the third at index 2. Index 1 therefore selects the int.

Why Tuple Positions Start at Zero

The elements of a tuple are numbered, starting with zero. This is different from a pair, whose two elements are given names: first and second. A pair lets you ask for its first element by name, but a tuple has no names for its elements at all. Position is the only handle you have, so every element must be identified by the number that marks where it sits.

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. This means that the first element is never reached with index 1, even though it may feel like the natural first position to a beginner. Once you accept that the numbering begins at zero, the rest of the access rules follow directly.

Position 0apple (string)Position 17 (int)Position 22.5 (double)
Which position does each element occupy when counting from zero, and which element does index 1 point to in a three-element tuple?

The diagram uses a string, an int and a double, the same kinds of values used in the standard example for this topic, with sample values added here for illustration. Reading the boxes from left to right gives the order of the elements. The number under each box is the value you pass to get. Index 1 selects the middle box, which holds the int, not the string.

Creating a Tuple with make_tuple

A tuple is commonly created with make_tuple, which lets the type of the tuple be deduced from the values you give it. You do not write out the type of each element yourself; the compiler works it out from the values. In the code below, the tuple holds a string, an int and a double, in that order.

python
Output (expected)
apple
7
2.5
Notes on the code
  • make_tuple builds the tuple and deduces each element's type from its value
  • get<0>(t) reads the element at position 0, the string
  • get<1>(t) reads the element at position 1, the int
  • get<2>(t) reads the element at position 2, the double

Retrieving Elements with get&lt;index&gt;

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 in the parentheses. Each call returns the element at the position named by the index. Because the index is part of the code itself, the compiler knows which slot is being read before the program runs. This is what the standard approach calls compile-time selection.

Worked example

Predicting the output of three get calls

A tuple t is built with make_tuple from the string "apple", the int 7 and the double 2.5. Predict what each of the three get calls prints.

  1. 1
    Identify the positions

    Counting from zero, the string is at index 0, the int at index 1 and the double at index 2.

  2. 2
    Evaluate get<0>(t)

    Index 0 selects the first element, so the call returns the string apple.

  3. 3
    Evaluate get<1>(t)

    Index 1 selects the second element, so the call returns the int 7, not the string.

  4. 4
    Evaluate get<2>(t)

    Index 2 selects the third element, so the call returns the double 2.5.

Result

The program prints apple, then 7, then 2.5.

Why get&lt;index&gt; Instead of get(t,1) or t[1]

A common first guess when learning tuples is that the elements can be reached the same way as any other collection: by writing the tuple's name followed by a number in square brackets, as in t[1], or by calling a generic function with the tuple and a number as arguments, as in get(t,1). Both guesses are treated as misconceptions for this purpose. The correct form for reading a tuple element is get<index>(tuple), because that form selects the element at compile time.

Access formStatus for tuple element selectionReason given
get<1>(t)The form used for element accessThe index is part of the code, giving compile-time selection
t[1]Named as a misconception for this purposeNot the way to select a tuple element at compile time
get(t,1)Named as a misconception for this purposeNot the way to select a tuple element at compile time

The three access forms as the topic presents them

get<1>(t)index written in the codet[1]named as a misconceptionget(t,1)named as a misconception
How does the index in get<1>(t) select a fixed slot at compile time, and how does that differ from the forms t[1] and get(t,1)?

The source is candid that the get<index> form is not elegant. It looks unusual compared with the bracket syntax many learners already know, and the author says it must be used anyway because it is the way to get compile-time selection of an element. Learners should expect the syntax to feel awkward at first and accept it as the standard form for tuple elements.

Tracing a Program to Find an Unexpected Value

When a tuple access gives a surprising result, the usual cause is a wrong index. When tracing a tuple access, first count the position from zero, then match the value at that position. Work through the program below one line at a time, writing down the index used by each get call and the value it returns.

Code walkthrough
#include <tuple>
#include <string>
#include <iostream>

int main() {
    auto t = std::make_tuple(std::string("apple"), 7, 2.5);
    std::cout << std::get<0>(t) << "\n";
    std::cout << std::get<1>(t) << "\n";
    std::cout << std::get<1>(t) << "\n";
    return 0;
}
  1. 1
    Line 1 creates the tuple, so position 0 holds apple, position 1 holds 7 and position 2 holds 2.5.
  2. 2
    The first output line calls get<0>(t), which returns apple.
  3. 3
    The second output line calls get<1>(t), which returns 7.
  4. 4
    The third output line calls get<1>(t) a second time, which again returns 7. If the programmer meant to print the first element again, the index should have been 0; the unexpected 7 is produced on this line.
  • The tuple has three elements: string at 0, int at 1, double at 2
  • The third printed line uses index 1 again, not index 0 as the author may have intended
Output
apple
7
7

Mistakes Beginners Make with Tuple Indexes

  • Common mistake

    Expecting the first element at index 1

    What it looks like

    Reading get<1>(t) and assuming it returns the string in a tuple that begins with a string.

    Why it fails

    Tuple elements are numbered starting from zero, so the first element is at index 0.

    Do this instead

    Read get<0>(t) for the first element and get<1>(t) for the second.

  • Common mistake

    Using t[1] to read a tuple element

    What it looks like

    Writing t[1] to get the second value of a tuple and expecting it to work the way it does with an ordinary array.

    Why it fails

    The source names t[1] as a misconception for tuple element selection.

    Do this instead

    Use get<1>(t) to select the element at position 1.

  • Common mistake

    Treating get(t,1) as the standard tuple access

    What it looks like

    Writing get(t,1) because it looks like a generic function call with the tuple and a number.

    Why it fails

    The source names get(t,1) as a misconception for compile-time element selection.

    Do this instead

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

  • Common mistake

    Looking for names on a tuple's elements

    What it looks like

    Trying to reach the elements of a tuple by names such as first and second, as is done with a pair.

    Why it fails

    A tuple has no names for its elements, so position is the only handle available.

    Do this instead

    Identify each element by its zero-based index.

Practicing Tuple Index Reads

EASY

A tuple t is created with make_tuple from the string "red", the int 3 and the double 1.5, in that order. Predict the output of the statement std::cout << std::get<2>(t) << and then check your answer by tracing the positions from zero.

Hints
  • Count the positions from zero: the string is at 0, the int at 1 and the double at 2.
  • Index 2 selects the third element, which is the double.

Key Takeaways

  • Tuple elements are numbered starting from zero, so the first element is at index 0 and the second at index 1.
  • A tuple element is read with get<index>(tuple), where the index sits inside the angle brackets.
  • The get<index> form is used because it gives compile-time selection; get(t,1) and t[1] are named as misconceptions for this purpose.
  • When an access returns an unexpected value, trace the program line by line, count each index from zero, and match the value at that position.

Related concepts

More concepts starting with T