Modern C++ — C++11 to C++23
C++ Version History
| Standard | Year | Key Features |
| C++98/03 | 1998/2003 | First standard, STL, templates, exceptions |
| C++11 | 2011 | auto, range-for, lambda, smart pointers, move semantics, nullptr, constexpr, threads |
| C++14 | 2014 | Generic lambdas, auto return type, make_unique |
| C++17 | 2017 | Structured bindings, if constexpr, std::optional, std::variant, filesystem |
| C++20 | 2020 | Concepts, Ranges, Coroutines, Modules, std::format, spaceship operator |
| C++23 | 2023 | std::print, std::expected, flat_map, deducing this |
C++11 — The Big Leap
C++11 Key Features
#include <iostream>
#include <vector>
#include <memory>
#include <thread>
using namespace std;
int main() {
// auto — type deduction
auto x = 42; // int
auto pi = 3.14; // double
auto name = "Alice"; // const char*
// Range-based for
vector<int> v = {1, 2, 3, 4, 5};
for (auto n : v) cout << n << " ";
cout << endl;
// Lambda
auto square = [](int x) { return x * x; };
cout << square(5) << endl; // 25
// nullptr (replaces NULL)
int *p = nullptr;
// Smart pointers
auto up = make_unique<int>(42);
auto sp = make_shared<string>("Hello");
cout << *up << " " << *sp << endl;
// Initializer lists
vector<int> nums = {10, 20, 30};
// Move semantics — transfer ownership without copying
vector<int> a = {1, 2, 3};
vector<int> b = move(a); // a is now empty, b owns the data
cout << "b size: " << b.size() << ", a size: " << a.size() << endl;
return 0;
}
C++17 — Structured Bindings and std::optional
C++17 Features
#include <iostream>
#include <map>
#include <optional>
#include <variant>
using namespace std;
// std::optional — value that may or may not exist
optional<int> divide(int a, int b) {
if (b == 0) return nullopt; // no value
return a / b;
}
int main() {
// Structured bindings — unpack pairs/tuples/structs
map<string, int> scores = {{"Alice", 95}, {"Bob", 87}};
for (const auto &[name, score] : scores) {
cout << name << ": " << score << endl;
}
// if with initializer
if (auto result = divide(10, 2); result.has_value()) {
cout << "Result: " << *result << endl; // 5
}
auto bad = divide(10, 0);
cout << bad.value_or(-1) << endl; // -1 (default)
// std::variant — type-safe union
variant<int, double, string> v;
v = 42;
cout << get<int>(v) << endl;
v = "Hello";
cout << get<string>(v) << endl;
return 0;
}
C++20 — Concepts and Ranges
C++20 Concepts and std::format
#include <iostream>
#include <format> // C++20
#include <concepts> // C++20
#include <ranges> // C++20
#include <vector>
using namespace std;
// Concept — constrain template types
template <typename T>
concept Numeric = integral<T> || floating_point<T>;
template <Numeric T>
T add(T a, T b) { return a + b; }
int main() {
// std::format — Python-style string formatting
string msg = format("Hello, {}! You are {} years old.", "Alice", 25);
cout << msg << endl;
cout << format("Pi = {:.4f}", 3.14159) << endl; // Pi = 3.1416
// Concepts
cout << add(3, 4) << endl; // 7 (int)
cout << add(1.5, 2.5) << endl; // 4.0 (double)
// add("a", "b"); // compile error — string is not Numeric
// Ranges — composable pipeline
vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto result = nums
| views::filter([](int n) { return n % 2 == 0; }) // even
| views::transform([](int n) { return n * n; }); // square
for (int n : result) cout << n << " "; // 4 16 36 64 100
cout << endl;
return 0;
}
// Compile: g++ -std=c++20 cpp20.cpp -o cpp20