Cpppair & tuple

pair & tuple

std::pair and std::tuple are simple utility types for grouping multiple values together without writing a dedicated struct or class. pair always holds exactly two values; tuple generalizes the idea to any number of values, of any types.
std::pair<T1, T2>
A pair groups exactly two values, which can be of different types, and exposes them through the .first and .second members.

pair_basics.cpp

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

int main() {
    std::pair<std::string, int> student("Alice", 92);

    std::cout << student.first << " scored " << student.second << std::endl;

    // make_pair deduces the types for you, avoiding explicit template args.
    auto entry = std::make_pair(std::string("Bob"), 85);
    std::cout << entry.first << " scored " << entry.second << std::endl;

    return 0;
}
std::pair shows up throughout the standard library — most notably, std::map<K, V> stores its elements as std::pair<const K, V>, and functions like map::insert return a pair indicating where an element landed and whether the insertion actually happened.
std::tuple<Types...>
A tuple generalizes pair to hold any number of values of any types, using the variadic template mechanism.

tuple_basics.cpp

CPP
#include <tuple>
#include <iostream>
#include <string>

int main() {
    std::tuple<std::string, int, double> record("Alice", 30, 5.6);

    // std::get<Index> accesses elements by position.
    std::cout << std::get<0>(record) << std::endl; // Alice
    std::cout << std::get<1>(record) << std::endl; // 30
    std::cout << std::get<2>(record) << std::endl; // 5.6

    auto t = std::make_tuple(1, "two", 3.0);
    std::cout << std::get<1>(t) << std::endl; // two

    return 0;
}
std::get's index must be a compile-time constant
Unlike array or vector indexing, you cannot use a runtime variable inside std::get<...> — the index (or type, for std::get<SomeType>(t) when the tuple has only one element of that type) must be known at compile time, because the compiler needs it to determine the return type. std::get<i> (t) where i is an int variable will not compile.
Structured bindings — the modern way to unpack
Repeatedly writing .first/.second or std::get<0>/std::get<1> is verbose. Since C++17, structured bindings let you unpack a pair or tuple into named variables in a single, readable line.

structured_bindings.cpp

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

std::pair<std::string, int> getStudent() {
    return {"Alice", 92};
}

int main() {
    // Old style:
    auto p = getStudent();
    std::cout << p.first << " " << p.second << std::endl;

    // Structured bindings — cleaner and self-documenting:
    auto [name, score] = getStudent();
    std::cout << name << " " << score << std::endl;

    std::tuple<int, double, std::string> t{1, 2.5, "three"};
    auto [a, b, c] = t;
    std::cout << a << " " << b << " " << c << std::endl;

    return 0;
}
Structured bindings work with pair, tuple, plain structs/classes with public members, and arrays — see the dedicated Structured Bindings page for the full picture, including how they interact with references and range-based for loops (for example, when iterating a std::map).
  • std::pair<T1, T2> groups exactly two values, accessed via .first/.second.

  • std::tuple<Types...> groups any number of values of any types, accessed via std::get<Index>(t).

  • std::get's index must be a compile-time constant, unlike array or vector indexing.

  • Structured bindings (auto [a, b] = pairOrTuple;) are the modern, preferred way to unpack both.