C++ STL
tuple
Complete lesson for tuple using LEARNCODEGURU’s 6-level learning model — from basics to advanced practice, with C++ OOP and STL where relevant.
Basics — tuple
Section: C++ STL. C++ std::tuple — store multiple values of mixed types, get/tie/structured bindings, and Tuple vs Pair.
What is a tuple?
std::tupleis a fixed-size collection of values that can have **different types**.- Unlike
pair(exactly 2), a tuple can hold **0, 1, 2, 3, …** elements. - Access by compile-time index:
get<0>(t),get<1>(t), … - Header:
#include - **Real-life:** a sealed pack of mixed items — name, age, score — opened by position.
| Idea | Meaning |
|---|---|
tuple | Heterogeneous fixed pack of values |
get(t) | Access element at index i |
tuple_size | Number of elements (compile-time) |
| Structured bindings | auto [a,b,c] = t; (C++17) |
Why use tuple?
- Return **multiple** values from a function without inventing a struct yet.
- Group related fields temporarily (x, y, z) or (ok, code, message).
- Unpack with
tie/ structured bindings. - Prefer a named **struct** when fields need lasting, readable names.
| Benefit | Example |
|---|---|
| Multi-return | tuple |
| Mixed types | tuple |
| Unpack | tie(a,b,c) = t; / auto [a,b,c]=t; |
| Generic code | Templates over tuple_size / get |
Differences between Tuple and Pair
- Same family of “bundle values together” — different size and access style.
| Feature | Tuple (std::tuple) | Pair (std::pair) |
|---|---|---|
| Element count | Any number (N) | Exactly 2 |
| Access | get(t) | first / second |
| Named members | No — index only | Yes — first, second |
| Header | | |
| Create | make_tuple, braces | make_pair, braces |
| Unpack | tie, structured bindings | Structured bindings / first-second |
std::ignore | Yes with tie | Less common pattern |
| Map element type | Not the map node type | pair |
| Nested readability | Better than nested pairs | Nested pairs get messy |
| When to prefer | 3+ values, or generic N | Always exactly two fields |
Creating a tuple
- Direct type list, braced init, or
make_tuple. make_tuplededuces types from arguments.forward_as_tuple(advanced) forwards references — for emplace-style APIs.
#include <iostream>
#include <string>
#include <tuple>
using namespace std;
int main() {
tuple<string, int, double> a("x", 1, 2.5);
tuple<string, int, double> b = {"y", 2, 3.5};
auto c = make_tuple(10, 'A', true);
cout << get<0>(a) << " " << get<1>(a) << " " << get<2>(a) << "\n";
return 0;
} Access with get and structured bindings
get(t)— index must be a **compile-time constant**.- C++17:
auto [x, y, z] = t;is usually clearer. tuple_size— how many elements.::value
#include <iostream>
#include <string>
#include <tuple>
using namespace std;
int main() {
tuple<string, int, double> t = {"Ann", 20, 9.5};
cout << get<0>(t) << "\n";
auto [name, age, score] = t;
cout << name << " " << age << " " << score << "\n";
return 0;
} tie — unpack into existing variables
std::tie(a, b, c) = t;assigns tuple elements into existing lvalues.std::ignoreskips a position:tie(a, ignore, c) = t;.- Older style still common; structured bindings often replace it for new locals.
#include <iostream>
#include <tuple>
using namespace std;
int main() {
int x = 0, z = 0;
auto t = make_tuple(10, 20, 30);
tie(x, ignore, z) = t;
cout << x << " " << z << "\n"; // 10 30
return 0;
} Returning multiple values
- Return a tuple instead of multiple out-parameters.
- Caller unpacks with structured bindings or
tie.
#include <iostream>
#include <tuple>
using namespace std;
tuple<int, int, int> stats(int a, int b, int c) {
int sum = a + b + c;
int mn = min(a, min(b, c));
int mx = max(a, max(b, c));
return {sum, mn, mx};
}
int main() {
auto [sum, mn, mx] = stats(3, 9, 1);
cout << sum << " " << mn << " " << mx << "\n";
return 0;
} Comparison of tuples
- Relational operators compare **lexicographically** left to right.
- Same idea as pair, extended to N elements.
#include <iostream>
#include <tuple>
using namespace std;
int main() {
auto a = make_tuple(1, 5, 9);
auto b = make_tuple(1, 5, 10);
cout << (a < b) << "\n"; // 1
return 0;
} Key points to remember
- tuple = N mixed values; pair = exactly 2 with first/second.
- Access with
getor structured bindings. tie+ignoreunpack into existing variables.- Prefer a struct when names matter long-term.
- Header
.
Advanced — tuple
tuple_cat and tuple_size
tuple_cat(t1, t2)concatenates tuples.tuple_size_v(C++17) gives the element count.
#include <iostream>
#include <tuple>
using namespace std;
int main() {
auto a = make_tuple(1, 2);
auto b = make_tuple(3);
auto c = tuple_cat(a, b); // 1,2,3
cout << tuple_size_v<decltype(c)> << "\n"; // 3
cout << get<2>(c) << "\n";
return 0;
} References in tuples
tiecreates a tuple of **references** to existing variables.make_tupleusually stores **values** (decays).- Be careful not to return references to locals via tuples.
Tuple vs struct
- Tuple: quick, anonymous positions — great for temporary multi-return.
- Struct: named fields, invariants, methods — better for lasting domain types.
- Nested tuples of tuples hurt readability — name a type instead.
| Aspect | Tuple | Struct |
|---|---|---|
| Field names | No | Yes |
| Access | Index / binding order | Member names |
| Best for | Short-lived bundles | Domain models |
| Refactor safety | Order-sensitive | Named — clearer |
apply (overview, C++17)
std::apply(f, t)callsfwith tuple elements as arguments.- Handy in generic code; optional for beginners.
Design tips
- 2 values → consider
pair; 3+ →tupleorstruct. - Document element order in a comment if you use tuple.
- Prefer structured bindings over deep
get<>chains. - Do not replace every struct with tuples — APIs become opaque.
Tricky Interview Points
Q1) What is std::tuple?
Answer A fixed-size heterogeneous collection that can store any number of values of mixed types.
Q2) Tuple vs pair?
Answer pair always has two elements (first/second); tuple can have N elements accessed by get<i> or structured bindings.
Q3) How do you access tuple elements?
Answer std::get<index>(t), or C++17 structured bindings auto [a,b,c] = t;
Q4) What does std::tie do?
Answer Creates a tuple of references used to assign from another tuple into existing variables; ignore skips a slot.
Q5) Header for tuple?
Answer <tuple>
Q6) How does tuple comparison work?
Answer Lexicographically from the first element to the last.
Q7) When prefer a struct over a tuple?
Answer When fields need meaningful names, invariants, or a stable public API.
Q8) Can a tuple hold references?
Answer Yes — e.g. via tie or tuple<int&> — but lifetime must be valid.
Q9) What is make_tuple?
Answer A helper that constructs a tuple with types deduced from its arguments.
Q10) What is tuple_cat?
Answer A function that concatenates two or more tuples into one.
Q11) Is get index runtime variable?
Answer No — the index template argument must be known at compile time.
Q12) Typical use of tuple in interviews?
Answer Return multiple results from a function, or store mixed fields briefly before unpacking.
Simple Programs
Create and get
#include <iostream>
#include <string>
#include <tuple>
using namespace std;
int main() {
tuple<string, int, double> t = {"x", 1, 2.5};
cout << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << "\n";
return 0;
} Structured bindings
#include <iostream>
#include <tuple>
using namespace std;
int main() {
auto t = make_tuple(10, 20, 30);
auto [a, b, c] = t;
cout << a << " " << b << " " << c << "\n";
return 0;
} tie and ignore
#include <iostream>
#include <tuple>
using namespace std;
int main() {
int a = 0, c = 0;
tie(a, ignore, c) = make_tuple(1, 2, 3);
cout << a << " " << c << "\n";
return 0;
} Return three values
#include <iostream>
#include <tuple>
using namespace std;
tuple<int, int, int> divmod(int n, int d) {
return {n / d, n % d, d};
}
int main() {
auto [q, r, d] = divmod(17, 5);
cout << q << " " << r << " " << d << "\n";
return 0;
} tuple comparison
#include <iostream>
#include <tuple>
using namespace std;
int main() {
cout << (make_tuple(1, 2, 3) < make_tuple(1, 2, 4)) << "\n";
return 0;
} tuple_cat
#include <iostream>
#include <tuple>
using namespace std;
int main() {
auto t = tuple_cat(make_tuple(1, 2), make_tuple("hi"));
cout << get<0>(t) << get<1>(t) << get<2>(t) << "\n";
return 0;
} Problem Solving Tricks
- tuple = N mixed values; pair = exactly two.
- get(t) — i is compile-time.
- auto [a,b,c] = t; for clear unpacking.
- tie(a,b,c) = t; into existing variables.
- ignore skips a tie slot.
- Lexicographic comparisons left to right.
- Prefer struct when names matter.
- make_tuple deduces types.
- tuple_cat concatenates packs.
- Header
. - Do not nest tuples deeply.
- Tuple vs Pair table is a common interview ask.
Practice Programs List
- Create tuple
and print with get<>. - Unpack with structured bindings.
- Use tie + ignore to assign first and third only.
- Write a function returning tuple of sum, min, max of three ints.
- Compare two 3-element tuples and explain the result.
- Concatenate two tuples with tuple_cat.
- Write Tuple vs Pair table in comments (8 rows).
- Write Tuple vs Struct table (5 rows).
- Store RGB as tuple
; print each channel. - Explain why get index cannot be a runtime variable.
- Refactor a nested pair-of-pairs into a tuple.
- List three APIs where multi-return via tuple helps.