Structs, Tuples & std::pair

struct, tuple ও pair

Read: ~25 min 14 practice problems

1. struct — Bundling Data

struct.cpp
#include <iostream>
#include <string>

struct Point {
    double x;
    double y;
};

struct Person {
    std::string name;
    int age;
};

int main() {
    Point p{3.0, 4.0};
    Person sara{"Sara", 21};

    std::cout << p.x << ", " << p.y << "\n";
    std::cout << sara.name << " " << sara.age << "\n";
}
struct vs class In C++, both can have functions, constructors, etc. The only difference: struct defaults to public; class defaults to private. Convention: use struct for plain data, class for encapsulated objects.

2. std::pair — Two of Anything

pair.cpp
#include <iostream>
#include <utility>

int main() {
    std::pair<int, std::string> p{42, "answer"};
    std::cout << p.first << " -> " << p.second << "\n";

    auto p2 = std::make_pair(3.14, 'a');
    std::cout << p2.first << " " << p2.second << "\n";
}

3. std::tuple — Any Number of Things

tuple.cpp
#include <iostream>
#include <tuple>
#include <string>

int main() {
    std::tuple<int, std::string, double> t{1, "x", 3.14};

    std::cout << std::get<0>(t) << " "
              << std::get<1>(t) << " "
              << std::get<2>(t) << "\n";
}

4. Structured Bindings (C++17) — The Killer Feature

Decompose a struct, pair, or tuple into named variables in one line:

bindings.cpp
#include <iostream>
#include <map>
#include <tuple>

std::tuple<int, int, int> stats() { return {3, 5, 7}; }

int main() {
    auto [a, b, c] = stats();
    std::cout << a << " " << b << " " << c << "\n";

    std::map<std::string, int> m = {{"a",1},{"b",2}};
    for (const auto& [key, value] : m)
        std::cout << key << "=" << value << "\n";
}

5. Aggregate Initialization

For simple structs (no constructors, all public), brace init by member order:

aggregate.cpp
struct Date { int day, month, year; };

Date today{9, 5, 2026};
Date birthday{.day=15, .month=8, .year=2003}; // designated init (C++20)

6. Practice Problems

  1. Define a struct Rectangle with width and height.
    ✨ Show Answer
    struct Rectangle { double width, height; };
  2. Add a method area() to Rectangle.
    ✨ Show Answer
    struct Rectangle {
        double width, height;
        double area() const { return width * height; }
    };
  3. Return two values (min, max) from a function.
    ✨ Show Answer
    std::pair<int,int> minMax(std::vector<int> v) {
        return {*std::min_element(v.begin(),v.end()),
                *std::max_element(v.begin(),v.end())};
    }
    auto [lo, hi] = minMax(v);
  4. Why prefer a struct over a tuple when fields have meaning?
    ✨ Show Answer

    Named fields are self-documenting. p.first vs p.x — the latter is clearer.

  5. Structured-bind a map iteration.
    ✨ Show Answer
    for (const auto& [k, v] : m) std::cout << k << ":" << v;
  6. Create a tuple of (string, int, double) and access each.
    ✨ Show Answer
    auto t = std::make_tuple("hi", 3, 2.5);
    std::cout << std::get<0>(t) << std::get<1>(t) << std::get<2>(t);
  7. Define a struct member with default value.
    ✨ Show Answer
    struct Config { int port = 8080; std::string host = "localhost"; };
  8. Default-constructed Point — what are x, y?
    ✨ Show Answer

    For non-class members (int, double), value-initialization with {} gives 0. With no initializer (Point p;), they're indeterminate.

  9. Compare two Points for equality.
    ✨ Show Answer
    struct Point {
        double x, y;
        bool operator==(const Point&) const = default; // C++20
    };
  10. Why does std::map use std::pair internally?
    ✨ Show Answer

    Each entry is a key-value pair. Iterating gives pair<const Key, Value>.

  11. Designated initializer (C++20) example.
    ✨ Show Answer
    Date d{.day=9, .month=5, .year=2026};
  12. Pass a struct to a function.
    ✨ Show Answer
    double area(const Rectangle& r) { return r.width * r.height; }

    Pass by const reference for any non-trivial struct.

  13. Build a vector of structs and find one by criteria.
    ✨ Show Answer
    std::vector<Person> ps = {{"a",20},{"b",30}};
    auto it = std::find_if(ps.begin(), ps.end(),
        [](const Person& p){ return p.age > 25; });
  14. Why prefer aggregate brace init over old-style assignment?
    ✨ Show Answer

    Brace init catches narrowing conversions and is consistent across all kinds of types (struct, std::pair, std::vector...).

Summary

Use struct when fields have meaning. Use std::pair/std::tuple for anonymous bundling and multi-return. Structured bindings (C++17) make decomposition trivial. For a class to behave as a value type, default the comparison operators (C++20).

Next Module → Midterm Project: Build a Real CLI Tool.