Skip to content
C++ Better Explained
Go back
C++ std::pair Explained: Store Two Values Together for Beginners
Edit page

C++ std::pair Explained: Store Two Values Together

Sometimes you need to group two related values — a name and a score, an x and y coordinate, a key and a result. std::pair is the standard C++ way to do exactly that, without defining a whole new struct.


What Is std::pair?

std::pair is a simple template container that holds exactly two values of potentially different types. You access them through .first and .second. It lives in the <utility> header (which is often included indirectly by other headers like <map>).

#include <iostream>
#include <utility>

int main() {
    std::pair<std::string, int> player = {"Alice", 95};

    std::cout << "Name: " << player.first << "\n";  // Alice
    std::cout << "Score: " << player.second << "\n"; // 95
    return 0;
}

Creating Pairs

There are three common ways to create a pair:

#include <iostream>
#include <utility>

int main() {
    // Method 1: direct construction
    std::pair<int, double> p1(1, 3.14);

    // Method 2: make_pair (deduces types automatically)
    auto p2 = std::make_pair(1, 3.14);

    // Method 3: brace initialization (C++11 and later)
    std::pair<int, double> p3 = {1, 3.14};

    std::cout << p1.first << ", " << p1.second << "\n"; // 1, 3.14
    return 0;
}

make_pair is the most common style since you don’t have to write out the types.


Pairs Are Commonly Used with Maps

Every element in a std::map is a std::pair<const Key, Value>. This is why you see .first and .second used when iterating over a map:

#include <iostream>
#include <map>

int main() {
    std::map<std::string, int> scores = {
        {"Alice", 95},
        {"Bob", 87},
        {"Carol", 92}
    };

    for (const auto& entry : scores) {
        // entry is a std::pair<const std::string, int>
        std::cout << entry.first << ": " << entry.second << "\n";
    }
    return 0;
}

Output:

Alice: 95
Bob: 87
Carol: 92
If you're looking to go deeper with C++, the C++ Better Explained Ebook is perfect for you — whether you're a complete beginner or looking to solidify your understanding. Just $19.

Returning Two Values from a Function

Before C++17 structured bindings, pair was the go-to way to return two values from a function without defining a struct:

#include <iostream>
#include <utility>
#include <string>

// Returns both a grade and whether it's passing
std::pair<char, bool> getGrade(int score) {
    if (score >= 90) return {'A', true};
    if (score >= 80) return {'B', true};
    if (score >= 70) return {'C', true};
    return {'F', false};
}

int main() {
    auto result = getGrade(85);
    std::cout << "Grade: " << result.first << "\n";   // B
    std::cout << "Passing: " << result.second << "\n"; // 1 (true)
    return 0;
}

C++17: Structured Bindings for Cleaner Pair Access

In C++17, you can unpack a pair into named variables using structured bindings, which is much more readable than .first and .second:

#include <iostream>
#include <map>

int main() {
    std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}};

    for (const auto& [name, score] : scores) {
        std::cout << name << " scored " << score << "\n";
    }
    return 0;
}

This is the modern preferred style when iterating maps or unpacking pairs.


Comparing Pairs

Pairs support comparison operators. They compare first first, then second as a tiebreaker:

#include <iostream>
#include <utility>

int main() {
    std::pair<int, int> a = {1, 5};
    std::pair<int, int> b = {1, 3};
    std::pair<int, int> c = {2, 0};

    std::cout << (a > b) << "\n"; // 1 (true) — same first, 5 > 3
    std::cout << (a < c) << "\n"; // 1 (true) — 1 < 2
    return 0;
}

This makes pairs naturally sortable, which is why they’re popular as keys in sorted containers or as entries in a vector you want to sort.


Practical Example: Sorting by Score

Here’s a complete example that uses a vector of pairs to sort students by score:

#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>

int main() {
    std::vector<std::pair<int, std::string>> students = {
        {87, "Bob"},
        {95, "Alice"},
        {72, "Carol"}
    };

    // Sort by score (first element) in descending order
    std::sort(students.begin(), students.end(),
        [](const auto& a, const auto& b) {
            return a.first > b.first;
        });

    for (const auto& [score, name] : students) {
        std::cout << name << ": " << score << "\n";
    }
    // Alice: 95
    // Bob: 87
    // Carol: 72
    return 0;
}

pair vs struct: Which Should You Use?

std::pairstruct
Setup neededNoneDefine the struct
Readability.first/.second can be unclearNamed fields are self-documenting
ReusabilityUse anywhere for two valuesBetter for reuse across files
STL compatibilityWorks natively with maps, algorithmsWorks too, but more boilerplate

Use pair for quick internal groupings — especially map entries and return values. Define a struct when the code will be read by others and the names of the two values matter for clarity.



Take Your C++ Further

If you’re looking to go deeper with C++, the C++ Better Explained Ebook is perfect for you — whether you’re a complete beginner or looking to solidify your understanding. Just $19.

👉 Get the C++ Better Explained Ebook — $19

📋

Free Download: The 10 Mistakes Every C++ Beginner Makes

A free 1-page checklist that shows the exact traps that slow down every C++ beginner — so you can avoid them from day one.

🔒 No spam. Unsubscribe anytime.


Edit page
Share this post on:

Previous Post
C++ Math Functions: Using the cmath Library for Beginners
Next Post
C++ Queue and Stack Tutorial: FIFO and LIFO Containers Explained