Standard Library[lib]
C++ pair: what std::pair is and how to use it
- Section
- Standard Library [lib]
- Standard
- C++17
- Compilers
- MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2, Clang 23.1 (libc++)
- Published
- Length
- 7 min read
Abstract
A C++ pair, std::pair from <utility>, holds two values, possibly of different types, as one object: std::pair<std::string, int> p{"Ana", 90}; makes one, and p.first and p.second read them. Since C++17 the types can be left off, and auto [name, score] = p; unpacks the pair into two named variables. == compares both parts; < compares first, then second when the firsts are equal, which is how std::sort orders a vector of pairs.

A C++ pair, std::pair from <utility>, holds exactly two values, possibly of different types, in one object. Create one with braces, std::, and read the two values as p.first and p.second. A std::map stores its entries as pairs, and a function can return one to hand back two values.
The smallest whole program, a name and a test score:
#include <iostream>
#include <string>
#include <utility>
int main() {
std::pair<std::string, int> p{"Ana", 90};
std::cout << p.first << '\n'; // Ana
std::cout << p.second << '\n'; // 90
p.second = 95;
std::cout << p.second << '\n'; // 95
}— end example]
It printed Ana, 90 and then 95: assigning to p.second changed the score inside the pair.
The samples are C++17, built with MSVC 19.44, Clang 19.1 (MSVC STL), GCC 16.2 and Clang 23.1 (libc++), and all four printed the same output for every one. Since When lists the first compiler releases that support each standard’s features.
How do you create a pair in C++?
Write the two types in angle brackets, then the values in braces. Since C++17 you can leave the types off and the compiler works them out from the values (class template argument deduction); std::make_pair does the same in code written before C++17:
std::pair<std::string, int> a{"Ana", 90}; // the types written out
std::pair b{3, 4.5}; // C++17: std::pair<int, double>
auto c = std::make_pair(3, 4.5); // the same, in older code
// ...
std::pair q{"Ana", 90}; // first is a const char*, not a string— end example]
The last line is the trap. With the types left off, "Ana" in quotes is a string literal, an array of characters, and the deduction turns it into a pointer: q.first was a const char*, not a std::string, on all four compilers. Write the types out, as for a, or write std::string("Ana").
How do you read first and second?
first and second are data members, variables stored inside the pair, so you read and assign them with a dot and no parentheses. Since C++17 a structured binding, a declaration that unpacks an object into named variables, gives the two values names of your own:
std::pair<std::string, int> p{"Ana", 90};
std::cout << p.first << '\n'; // Ana
std::cout << p.second << '\n'; // 90
auto [name, score] = p; // C++17: copies of first and second
std::cout << name << '\n'; // Ana
std::cout << score << '\n'; // 90
auto& [n, s] = p; // n and s are p.first and p.second themselves
s = 95;
std::cout << n << '\n'; // Ana
std::cout << p.second << '\n'; // 95: the pair changed
std::cout << score << '\n'; // 90: the copy did not— end example]

With plain auto, the names belong to a copy of the pair, so changing score leaves p alone. auto& names the pair’s own members: setting s to 95 changed p.second, while the copy’s score still printed 90.
Because first is a member and not a function, p.first() does not compile:
std::cout << p.first() << '\n'; // error: first is not a function— end example]
Clang with libc++ said:
error: type 'std::string' does not provide a call operator— end example]
The other three compilers reject it too.
How do you compare two pairs?
== is true when both parts are equal. < compares the first values and looks at second only when the firsts are equal, the way a dictionary orders words by their first letter before the next (the standard’s definition):
std::pair<std::string, int> ana{"Ana", 90};
std::pair<std::string, int> ana_again{"Ana", 90};
std::pair<std::string, int> ana_retake{"Ana", 72};
std::pair<std::string, int> ben{"Ben", 72};
std::cout << std::boolalpha;
std::cout << (ana == ana_again) << '\n'; // true: both parts equal
std::cout << (ana == ana_retake) << '\n'; // false: 90 and 72
std::cout << (ana < ben) << '\n'; // true: "Ana" < "Ben"
std::cout << (ben < ana) << '\n'; // false, though 72 < 90
std::cout << (ana_retake < ana) << '\n'; // true: 72 < 90 decides— end example]
All four printed the results in the comments. ben < ana is false although 72 is less than 90: the names decide first, and “Ben” comes after “Ana”. !=, >, <= and >= follow the same order.
How do you make a vector of pairs and sort it?
Write the pair type inside the std::vector’s angle brackets and add pairs with push_back({"Cy", 90}), or with emplace_back("Ben", 72), which builds the pair inside the vector from the two values. std::sort (from <algorithm>) with no comparison uses the pairs’ <, so it orders by first, then by second. A lambda, a small function written in place, sorts by second instead:
std::vector<std::pair<std::string, int>> scores;
scores.push_back({"Cy", 90});
scores.push_back({"Ana", 90});
scores.emplace_back("Ben", 72); // builds the pair in place
std::sort(scores.begin(), scores.end()); // by first, then second
for (const auto& p : scores) {
std::cout << p.first << ' ' << p.second << '\n';
}
std::cout << '\n';
std::sort(scores.begin(), scores.end(),
[](const auto& a, const auto& b) {
return a.second > b.second; // highest score first
});
for (const auto& p : scores) {
std::cout << p.first << ' ' << p.second << '\n';
}— end example]
It printed, on all four:
Ana 90
Ben 72
Cy 90
Ana 90
Cy 90
Ben 72— end example]
The two 90s came out Ana, then Cy, the order they had before the second sort. std::sort does not promise that order for elements that compare equal; std::stable_sort keeps tied elements in order.
How does a std::map use pairs?
Every element of a std::map is a pair: the key in first, the value in second. The key is const, so it cannot be changed in place. A range-for with a structured binding reads both, and insert hands back a pair of its own: an iterator to the element (a position in the map) and a bool that says whether it was added:
std::map<std::string, int> scores{{"Ben", 72}, {"Ana", 90}};
// Each element is a pair whose key is const.
static_assert(std::is_same_v<std::map<std::string, int>::value_type,
std::pair<const std::string, int>>);
std::cout << std::boolalpha;
auto added = scores.insert({"Cy", 90});
std::cout << added.second << '\n'; // true: Cy is new
std::cout << added.first->first << '\n'; // Cy
auto kept = scores.insert({"Ana", 50});
std::cout << kept.second << '\n'; // false: Ana was there
std::cout << kept.first->second << '\n'; // 90: left as it was
for (const auto& [name, score] : scores) {
std::cout << name << ' ' << score << '\n';
}— end example]
The static_assert passed on all four. The second insert returned false and left Ana at 90, and the loop printed Ana 90, Ben 72 and Cy 90, in name order although Ben went in first.
Should you use a pair or a struct?
Use a pair when the two values need no names of their own, such as a key and its value, or the iterator and bool that insert returns. When they do, a struct reads better: range.min says more than range.first. A function can return a pair, and a structured binding at the call names the two values:
std::pair<int, int> score_range(const std::vector<int>& scores) {
int low = scores.front();
int high = scores.front();
for (int s : scores) {
low = std::min(low, s);
high = std::max(high, s);
}
return {low, high};
}
int main() {
std::vector<int> scores{90, 72, 90}; // Ana, Ben, Cy
auto [low, high] = score_range(scores);
std::cout << low << '\n'; // 72
std::cout << high << '\n'; // 90
}— end example]
It printed 72 and 90. score_range needs at least one score: front() on an empty vector is undefined behavior. For your own functions, though, the Core Guidelines prefer a struct (F.21), which unpacks the same way; std::tie, pair and tuple covers that choice, std::tuple and std::tie.
A std::pair cheat sheet
| To | Write |
|---|---|
| Create one | std:: |
| Create without the types (C++17) | std::pair b{3, 4.5}; |
| Create in older code | std:: |
| Read the values | p.first, p.second (no parentheses) |
| Unpack (C++17) | auto [name, score] = p; |
| Unpack and change the pair | auto& [n, s] = p; |
| Compare | == checks both; < checks first, then second |
| A vector of pairs | std:: |
| Sort by first, then second | std:: |
| Sort by second, highest first | a lambda returning a.second > b.second |
| Loop over a map | for (const auto& [name, score] : scores) |
The Standard Library section has the other answers on the library’s containers and algorithms.
Questions
Which header is std::pair in?
std::pair is declared in <utility>. Include that header in any file that writes std::pair, even when another header it uses, such as <map>, already works with pairs.
What is the difference between std::pair and std::make_pair?
std::pair is the type; std::make_pair is a function that builds one and works out the two types from its arguments, so std::make_pair(3, 4.5) is a std::pair<int, double>. Since C++17, braces without the types, std::pair b{3, 4.5};, give the same type, so new code can do without make_pair. Both turn a quoted "Ana" into a const char*, not a std::string.
Can a pair hold two different types?
Yes. The two types are separate template arguments, so a std::pair<std::string, int> holds a string and an int. They can also be the same, as in a std::pair<int, int> holding a lowest and a highest score.
How do you sort a vector of pairs by the second value?
Pass std::sort a lambda that compares the second members: std::sort(v.begin(), v.end(), [](const auto& a, const auto& b) { return a.second > b.second; }); puts the highest second value first, and < instead of > puts the lowest first. std::sort does not promise to keep tied pairs in their order; std::stable_sort does.
What is the difference between a pair and a tuple?
A std::pair holds exactly two values, read as first and second. A std::tuple, from <tuple>, holds any number of values and is read with std::get by position. A pair is the two-value case of the same idea.
How do you swap the two values of a pair?
Call std::swap on its two members: for std::pair<int, int> range{90, 72};, std::swap(range.first, range.second); leaves first at 72 and second at 90. std::swap exchanges two objects of one type, so this works only when both parts have the same type, as two ints do.
Sources
- std::paircppreference.com
- deduction guides for std::paircppreference.com
- std::make_paircppreference.com
- [pairs.spec] Specialized algorithmsC++ standard working draft
- Structured binding declarationcppreference.com
- std::map::insertcppreference.com