pair
TypeBefore we look at the operations on associative containers, we need to know about the library type named pair
, which is defined in the utility
header.
A pair
holds two data members. Like the containers, pair
is a template from which we generate specific types. We must supply two type names when we create a pair
. The data members of the pair
have the corresponding types. There is no requirement that the two types be the same:
pair<string, string> anon; // holds two strings
pair<string, size_t> word_count; // holds a string and an size_t
pair<string, vector<int>> line; // holds string and vector<int>
The default pair
constructor value initializes (§ 3.3.1, p. 98) the data members. Thus, anon
is a pair
of two empty string
s, and line
holds an empty string
and an empty vector
. The size_t
value in word_count
gets the value 0, and the string
member is initialized to the empty string
.
We can also provide initializers for each member:
pair<string, string> author{"James", "Joyce"};
creates a pair
named author
, initialized with the values "James
" and "Joyce
".
Unlike other library types, the data members of pair
are public
(§ 7.2, p. 268). These members are named first
and second
, respectively. We access these members using the normal member access notation (§ 1.5.2, p. 23), as, for example, we did in the output statement of our word-counting program on page 421:
// print the results
cout << w.first << " occurs " << w.second
<< ((w.second > 1) ? " times" : " time") << endl;
Here, w
is a reference to an element in a map
. Elements in a map
are pair
s. In this statement we print the first
member of the element, which is the key, followed by the second
member, which is the counter. The library defines only a limited number of operations on pair
s, which are listed in Table 11.2.
pair
ObjectsImagine we have a function that needs to return a pair
. Under the new standard we can list initialize the return value (§ 6.3.2, p. 226):
pair<string, int>
process(vector<string> &v)
{
// process v
if (!v.empty())
return {v.back(), v.back().size()}; // list initialize
else
return pair<string, int>(); // explicitly constructed return value
}
If v
isn’t empty, we return a pair
composed of the last string
in v
and the size of that string
. Otherwise, we explicitly construct and return an empty pair
.
Under earlier versions of C++, we couldn’t use braced initializers to return a type like pair
. Instead, we might have written both returns to explicitly construct the return value:
if (!v.empty())
return pair<string, int>(v.back(), v.back().size());
Alternatively, we could have used make_pair
to generate a new pair
of the appropriate type from its two arguments:
if (!v.empty())
return make_pair(v.back(), v.back().size());
Exercise 11.12: Write a program to read a sequence of string
s and int
s, storing each into a pair
. Store the pair
s in a vector
.
Exercise 11.13: There are at least three ways to create the pair
s in the program for the previous exercise. Write three versions of that program, creating the pair
s in each way. Explain which form you think is easiest to write and understand, and why.
Exercise 11.14: Extend the map
of children to their family name that you wrote for the exercises in § 11.2.1 (p. 424) by having the vector
store a pair
that holds a child’s name and birthday.