Concepts / Using the pair Utility

Using the pair Utility

Make_pair() is a guideline to consider, not a requirement, and explicit types remain valid.

  • Programming

Choosing a Container That Fits the Data

A container is a structure that holds other values. Writing C++ well means choosing a container that matches the shape of your data, not simply the first one that comes to mind. This article looks at two practical guidelines from the C++ Standard Library. The first says that when the size of a sequence is fixed at compile time, an array is a sensible choice. The second says that when you create a pair, make_pair() can simplify the code by letting the compiler deduce the types.

Both guidelines are about what the program can know ahead of time. The size of the container and the types inside a pair are facts that the compiler can sometimes settle before the program runs. Following the trace in this article, you will see how each choice changes what the program knows at each step.

What a Constexpr Size Means

Definition

A constexpr value is a value known when the program is compiled, not when it runs. Use an array when a sequence has a constexpr size, meaning its length is fixed at compile time.

A good example is the number of sensor channels a program is built to read. If that number is decided ahead of time and does not change while the program runs, it can be declared as a constexpr value and used as the size of the array. A constexpr size is what makes an array a good fit. When the size of a sequence is decided only at run time, a different choice is needed.

cpp
Notes on the code
  • kChannels is fixed when the program is compiled, so it can serve as the array size.
  • The array holds exactly four elements, and that count never changes afterward.
  • readings[2] reaches the third element directly by its index.

The example above applies the size guideline. Read the declaration first, then the access that follows it. The number of readings comes from a constexpr value, and the array is declared with that value as its size.

Tracing What the Program Knows

Follow the array example one stage at a time. Each stage adds to or relies on what the program already knows about the container. The diagram below shows the sequence of facts.

Compile timekChannels = 4 is knownDeclarationroom for 4 elementsRead readings[2]reached by index, no sizecheck neededLater in programsize still 4, unchangedsize fixedindex accesssize never changes
At each stage, which facts about the array's size and contents are known, and how does using a fixed-size array keep the size knowledge stable?

The first fact is settled at compile time: the size is 4. When the declaration runs, the array has room for four elements, and that number never changes afterward, because it came from a compile-time value. Each element is then reached by its index. The program does not need to ask how many elements exist before reading one, because the size was settled earlier. Keeping this sequence of facts in mind shows why a fixed size is a useful design choice.

Indices Into a Fixed Block of Elements

Each element of the array sits at a position that its index identifies. Index 0 is the first element, index 1 is the second, and so on up to the last one. Because the size is fixed, the set of valid indices is also fixed. The diagram below maps each index of the readings array to the value stored there.

readings[0]12readings[1]47readings[2]30readings[3]8next indexnext indexnext index
How does each index in the fixed-size readings array map to one stored element?

Choosing Between an Array and a Resizable Container

The array guideline depends on the size being known at compile time. If the number of elements is decided only while the program runs, a fixed-size array is the wrong tool, and a different, resizable container is the better choice. The table below compares the two on the points that matter when choosing.

QuestionArray with a constexpr sizeResizable container
When is the size settled?At compile time, from a constexpr valueWhile the program runs
Can the number of elements change?No, it stays fixedYes, it can grow or shrink
What fits the data?A sequence whose length is a fixed quantity decided ahead of timeA sequence whose length is not known until run time
What the program knows at each stepThe size is known from the declaration onwardThe current size must be checked or tracked as the program runs

Fixed-size arrays and resizable containers differ in when the size is known and whether it can change.

Creating Pairs With make_pair

A pair holds two values together as one object. The second guideline concerns pairs: when you create one, make_pair() can simplify the code. Make_pair() is a guideline to consider, not a requirement, and explicit types remain valid. Type deduction is the mechanism that makes it work. The compiler works out the element types from the values you give it, so you do not have to write them yourself.

cpp
Notes on the code
  • The first declaration names both element types, int and double, in the type itself.
  • The second declaration writes no element types; make_pair() takes them from the arguments 3 and 2.5.
  • Both declarations produce a pair that holds an int and a double.

Without make_pair(), you name both types in the declaration. With it, the types come from the arguments. Compare how much you have to type in each case. In the second line, the compiler reads the value 3 and the value 2.5, then chooses the types that match them.

3int valuemake_pair()deduces the element typesstd::pair<int,double>returned pair2.5double valuetype inttype doublereturns
How do the argument types passed to make_pair() flow into the deduced std::pair type that is returned?

What do you think happens?

Given the values 3 and 2.5, what type is the pair that make_pair() returns?

  • std::pair<int, int>

  • std::pair<int, double>

  • std::pair<double, double>

Reveal answer
Answer:

std::pair<int, double>

make_pair() deduces each element type from its argument: 3 is an int and 2.5 is a double, so the returned pair holds an int and a double.

Once a pair exists, its two values are reached through its first and second members. The pair does not change the types it was built with, so the values you read from first and second have the types the pair was created with.

Mistakes Beginners Make With Containers and Pairs

  • Common mistake

    Using a constexpr size for a count that is only known at run time

    What it looks like

    constexpr int n = read_count_from_user(); (a value that comes from input)

    Why it fails

    A constexpr value must be known when the program is compiled. A count read from input is not known then.

    Do this instead

    Use a resizable container when the number of elements is decided while the program runs.

  • Common mistake

    Assuming make_pair() is required

    What it looks like

    Writing std::make_pair(3, 2.5) when you want to state the types yourself

    Why it fails

    make_pair() is a guideline to consider, not a requirement. Explicit types remain valid.

    Do this instead

    Write std::pair<int, double> explicitly whenever naming the types makes the code clearer.

  • Common mistake

    Expecting make_pair() to produce a type you did not pass in

    What it looks like

    auto p = std::make_pair(3, 2.5f); assuming the result holds a double

    Why it fails

    Type deduction takes each element type from its argument, and 2.5f is a float.

    Do this instead

    Read the argument types to predict the pair type, or write the type explicitly.

  • Common mistake

    Treating a fixed-size array as if it can grow when more elements arrive

  • Common mistake

    Forgetting that the valid indices of a fixed-size array stop at size minus one

Practice Choosing and Predicting

EASY

A program reads exactly 6 sensor channels, a fixed hardware count known when the program is built. Would you store the readings in an array with a constexpr size or in a resizable container? Explain which facts the program knows at the declaration.

Hints
  • Ask whether the count is known at compile time.
  • Think about whether the number of elements can change while the program runs.
MEDIUM

Write one declaration that stores the name "alpha" and the value 9 in a pair without naming the element types, then state the type the compiler deduces.

Hints
  • make_pair() deduces types from its arguments.
  • A string literal in double quotes has a type that the compiler works out from the literal itself.

Key Takeaways

  • Use an array when a sequence has a constexpr size, meaning its length is fixed at compile time.
  • A constexpr value is known when the program is compiled, so an array declared with it has a size that never changes afterward.
  • make_pair() simplifies pair creation through type deduction: the compiler determines the element types from the values, and explicit types remain valid.
  • Choose the container that matches the shape of your data; when the size is only known at run time, use a different, resizable container.

Related concepts

More concepts starting with U