SyntaxStudy
Sign Up
C++ C++17/20 Features: Structured Bindings, if constexpr, Concepts
C++ Beginner 1 min read

C++17/20 Features: Structured Bindings, if constexpr, Concepts

C++17 structured bindings allow a single declaration to decompose a pair, tuple, array, or any aggregate into named variables. The syntax 'auto [a, b] = pair;' is far more readable than accessing 'pair.first' and 'pair.second'. Structured bindings work in range-for loops, switch statements with 'init statements', and any context that accepts a declaration. 'if constexpr' evaluates a compile-time boolean condition and discards the branch not taken without emitting code for it. This replaces the fragile technique of partial template specialisation used in earlier standards for compile-time branching inside function templates. The discarded branch is parsed but not instantiated, so it may contain code that would be ill-formed for other types. C++20 concepts allow constraints to be placed on template parameters, turning cryptic template substitution failures into clear, readable compiler errors. A concept is a named boolean predicate evaluated at compile time. The 'requires' clause attaches constraints to a template, and the 'concept' keyword defines reusable named constraints. Together, concepts make generic code more expressive, self-documenting, and easier to diagnose.
Example
#include <iostream>
#include <map>
#include <string>
#include <type_traits>
#include <concepts>   // C++20

// C++20 Concept: requires arithmetic type
template<typename T>
concept Numeric = std::is_arithmetic_v<T>;

// Constrained function template
template<Numeric T>
T square(T value) { return value * value; }

// if constexpr: compile-time branching inside template
template<typename T>
std::string describe(T val) {
    if constexpr (std::is_integral_v<T>)
        return "integer: " + std::to_string(val);
    else if constexpr (std::is_floating_point_v<T>)
        return "float: " + std::to_string(val);
    else
        return "other";
}

int main() {
    // Structured bindings with map iteration (C++17)
    std::map<std::string, int> inventory = {
        {"apples", 10}, {"bananas", 5}, {"cherries", 25}
    };
    for (const auto& [item, qty] : inventory)
        std::cout << item << ": " << qty << "\n";

    // Structured binding with pair
    auto [q, r] = std::pair{17 / 5, 17 % 5};
    std::cout << "17 / 5 = " << q << " remainder " << r << "\n";

    // if constexpr in template
    std::cout << describe(42)   << "\n";
    std::cout << describe(3.14) << "\n";

    // Concepts: square only works for Numeric types
    std::cout << "square(7)   = " << square(7)   << "\n";
    std::cout << "square(2.5) = " << square(2.5) << "\n";
    // square("hi") would be a clear concept violation error

    return 0;
}