Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. C++ Dictionary
  3. std::tuple / std::pair

std::tuple / std::pair

In C++, std::tuple and std::pair are template classes for grouping multiple values together. pair holds exactly two values, while tuple can hold any number of values. They are useful when you want to return multiple values from a function or bundle values of different types into a single object.

Syntax

// ========================================
// std::pair basic syntax
// ========================================
#include <utility>  // required to use pair

// Create a pair (explicit type version)
std::pair<Type1, Type2> varName = std::make_pair(val1, val2);

// Access pair elements
varName.first   // access the first value
varName.second  // access the second value

// ========================================
// std::tuple basic syntax
// ========================================
#include <tuple>  // required to use tuple

// Create a tuple
std::tuple<Type1, Type2, Type3> varName = std::make_tuple(val1, val2, val3);

// Access tuple elements (index must be a compile-time constant)
std::get<0>(varName)  // access element at index 0
std::get<1>(varName)  // access element at index 1
std::get<2>(varName)  // access element at index 2

// Decompose (unpack) using tie()
std::tie(varA, varB, varC) = tupleVar;

// Use std::ignore to skip unwanted elements
std::tie(varA, std::ignore, varC) = tupleVar;

Syntax Reference

Syntax / FunctionDescription
std::pair<T1, T2>A template class that groups two values. Access via .first and .second.
std::make_pair(a, b)A helper function that creates a pair concisely using type deduction.
std::tuple<T1, T2, ...>A template class that groups any number of values of any types.
std::make_tuple(a, b, ...)A helper function that creates a tuple concisely using type deduction.
std::get<N>(t)Retrieves the N-th element (0-based) of a tuple or pair. N must be a compile-time constant.
std::tie(a, b, ...)Creates a tuple of references to variables and decomposes (unpacks) a tuple on the right side into each variable.
std::ignoreA placeholder used with std::tie() to skip unwanted elements.
std::tuple_size<T>::valueRetrieves the number of elements in a tuple at compile time.

Sample Code

sg_labmem_data.cpp
// ========================================
// sg_labmem_data.cpp
// Manages Steins;Gate lab members using tuple/pair,
// bundling name, role, lab-member number,
// and time-leap count together.
// ========================================

#include <iostream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

// ========================================
// Returns name and lab-member number
// bundled together as a pair
// ========================================
std::pair<std::string, int> getLabMemberBasic(int index) {
    // pair of lab-member name and number
    std::pair<std::string, int> members[5];
    members[0] = std::make_pair("Okabe Rintaro",  1);
    members[1] = std::make_pair("Shiina Mayuri",  2);
    members[2] = std::make_pair("Hashida Itaru",  3);
    members[3] = std::make_pair("Makise Kurisu",  4);
    members[4] = std::make_pair("Amane Suzuha",   8);

    if (index >= 0 && index < 5) {
        return members[index];
    }
    return std::make_pair("Unknown", 0);
}

// ========================================
// Returns four pieces of information—name, role,
// lab-member number, and time-leap count—bundled in a tuple
// ========================================
std::tuple<std::string, std::string, int, int> getLabMemberDetail(const std::string& name) {
    // name / role / lab-member number / time-leap count
    if (name == "Okabe Rintaro") {
        return std::make_tuple("Okabe Rintaro",  "Lab leader, inventor",        1, 3);
    } else if (name == "Makise Kurisu") {
        return std::make_tuple("Makise Kurisu",  "Theoretical physics",         4, 0);
    } else if (name == "Amane Suzuha") {
        return std::make_tuple("Amane Suzuha",   "Time-machine maintenance",    8, 1);
    }
    return std::make_tuple("Unknown", "Unknown", 0, 0);
}

int main() {
    std::cout << "=== Future Gadget Lab Member Information System ===" << std::endl << std::endl;

    // ----------------------------------------
    // Basic usage of pair
    // ----------------------------------------
    std::cout << "--- pair: lab-member name and number ---" << std::endl;

    std::pair<std::string, int> m0 = getLabMemberBasic(0);
    std::pair<std::string, int> m3 = getLabMemberBasic(3);

    // use .first for name and .second for number
    std::cout << "Member: " << m0.first << "  Number: " << m0.second << std::endl;
    std::cout << "Member: " << m3.first << "  Number: " << m3.second << std::endl;
    std::cout << std::endl;

    // ----------------------------------------
    // Storing pairs in a vector
    // ----------------------------------------
    std::cout << "--- pair vector: divergence meter readings ---" << std::endl;

    std::vector<std::pair<std::string, double> > divergenceLog;
    divergenceLog.push_back(std::make_pair("Alpha world line",   1.048596));
    divergenceLog.push_back(std::make_pair("Beta world line",    0.571024));
    divergenceLog.push_back(std::make_pair("Steins Gate",        1.048596));

    for (int i = 0; i < (int)divergenceLog.size(); i++) {
        std::cout << divergenceLog[i].first << "  divergence: " << divergenceLog[i].second << std::endl;
    }
    std::cout << std::endl;

    // ----------------------------------------
    // Using tuple to bundle four values
    // ----------------------------------------
    std::cout << "--- tuple: detailed member information ---" << std::endl;

    std::tuple<std::string, std::string, int, int> detail = getLabMemberDetail("Okabe Rintaro");

    // access each element with std::get<index>()
    std::cout << "Name:             " << std::get<0>(detail) << std::endl;
    std::cout << "Role:             " << std::get<1>(detail) << std::endl;
    std::cout << "Member number:    " << std::get<2>(detail) << std::endl;
    std::cout << "Time-leap count:  " << std::get<3>(detail) << std::endl;
    std::cout << std::endl;

    // ----------------------------------------
    // Unpacking a tuple with std::tie()
    // ----------------------------------------
    std::cout << "--- tie(): unpacking a tuple ---" << std::endl;

    std::string memberName, role;
    int labNumber, leapCount;

    // assign all tuple values to variables at once with tie()
    std::tie(memberName, role, labNumber, leapCount) = getLabMemberDetail("Makise Kurisu");

    std::cout << memberName << " / " << role << " / Member " << labNumber
              << " / Time leaps: " << leapCount << std::endl;
    std::cout << std::endl;

    // ----------------------------------------
    // Skipping unwanted elements with std::ignore
    // ----------------------------------------
    std::cout << "--- ignore: skip unwanted elements ---" << std::endl;

    std::string targetName;
    int targetLeapCount;

    // role and member number are not needed, so use std::ignore
    std::tie(targetName, std::ignore, std::ignore, targetLeapCount) = getLabMemberDetail("Amane Suzuha");

    std::cout << targetName << "  Time-leap count: " << targetLeapCount << std::endl;
    if (targetLeapCount > 0) {
        std::cout << "  -> A time traveler from the future." << std::endl;
    }

    return 0;
}
# Compile
g++ -std=c++11 sg_labmem_data.cpp -o sg_labmem_data

# Run
./sg_labmem_data
=== Future Gadget Lab Member Information System ===

--- pair: lab-member name and number ---
Member: Okabe Rintaro  Number: 1
Member: Makise Kurisu  Number: 4

--- pair vector: divergence meter readings ---
Alpha world line  divergence: 1.04860
Beta world line  divergence: 0.57102
Steins Gate  divergence: 1.04860

--- tuple: detailed member information ---
Name:             Okabe Rintaro
Role:             Lab leader, inventor
Member number:    1
Time-leap count:  3

--- tie(): unpacking a tuple ---
Makise Kurisu / Theoretical physics / Member 4 / Time leaps: 0

--- ignore: skip unwanted elements ---
Amane Suzuha  Time-leap count: 1
  -> A time traveler from the future.

Common Mistakes

When using std::tuple and std::pair, watch out for out-of-range index access with get<> and type-deduction surprises in structured bindings.

Out-of-range index in get<>

If N in std::get<N>(t) is equal to or greater than the number of elements in the tuple, it is a compile error. This can be caught at compile time rather than at runtime, but be careful not to accidentally access the wrong element due to a type mismatch. Use std::tuple_size<T>::value to check the element count.

NG: out-of-range index (compile error)
#include <tuple>
#include <string>

int main() {
    // tuple with 3 elements (valid indices are 0, 1, and 2 only)
    std::tuple<std::string, int, double> t("Okabe Rintaro", 1, 1.048596);

    // NG: index 3 is equal to the element count (3), so this is a compile error
    std::get<3>(t);
    return 0;
}
OK: valid indices and checking with tuple_size
#include <iostream>
#include <tuple>

int main() {
    std::tuple<std::string, int, double> t("Okabe Rintaro", 1, 1.048596);

    std::cout << std::get<0>(t) << std::endl;  // Okabe Rintaro
    std::cout << std::get<1>(t) << std::endl;  // 1
    std::cout << std::get<2>(t) << std::endl;  // 1.048596

    // use tuple_size to check the element count
    constexpr int size = std::tuple_size<decltype(t)>::value;
    std::cout << "element count: " << size << std::endl;  // 3

    return 0;
}

Type-deduction mistake in structured bindings (C++17)

C++17 structured bindings (auto [a, b, c] = t;) are convenient, but they copy by default. If you want changes to be reflected back in the original tuple, you must use a reference: auto& [a, b, c] = t;. Using const auto& makes it read-only.

NG: value copy does not update the original tuple
#include <iostream>
#include <tuple>

int main() {
    std::tuple<std::string, int> labMem("Shiina Mayuri", 2);

    // NG: received as a value copy, so the change is not reflected in the original tuple
    auto [name1, num1] = labMem;
    num1 = 99;  // labMem is not changed
    std::cout << "After copy (original value): " << std::get<1>(labMem) << std::endl;  // still 2

    return 0;
}
OK: reference binding reflects changes in the original
#include <iostream>
#include <tuple>

int main() {
    std::tuple<std::string, int> labMem("Shiina Mayuri", 2);

    // OK: received as a reference, so the change is reflected
    auto& [name2, num2] = labMem;
    num2 = 99;  // labMem is updated
    std::cout << "After reference (updated): " << std::get<1>(labMem) << std::endl;  // 99

    return 0;
}

Overview

std::pair requires the <utility> header and std::tuple requires the <tuple> header. pair is specialized for two elements and provides intuitively named access via .first and .second, making it a natural fit for map key-value pairs and returning two values from a function. tuple is useful when three or more elements are needed; access individual elements with std::get<N>(). When returning multiple values, std::tie() makes unpacking concise. Unwanted elements can be skipped with std::ignore. Note that in C++03, declaring a vector of pairs required a space between the closing angle brackets (vector<pair<T1, T2> >), but since C++11 >> is fine as well. When the number of elements or types becomes large and the code becomes hard to read, consider defining a struct or class with named member variables instead.

If you find any errors or copyright issues, please .