Modern C++ has seen a series of significant updates starting from C++11, each bringing new features and enhancements that aim to make the language more efficient, readable, and maintainable. Here’s a brief overview of the major features introduced in each version since C++11, along with a comment on their usage:
C++11
C++11 marked a significant evolution in the C++ language, introducing several powerful features that modernized and simplified C++ programming. Here are some of the most impactful features, along with examples to illustrate their usage:
1. Auto type Deduction
The auto keyword allows the compiler to automatically deduce the type of a variable from its initializer.
auto x = 42; // int auto y = 3.14; // double auto s = "hello"; // const char*
2. Lambda Expressions
Lambdas provide a concise way to define anonymous functions directly in your code.
auto add = [](int a, int b) { return a + b; };
int result = add(3, 4);  // result is 73. Range-based for Loops
Simplifies iteration over collections like arrays, vectors, and other containers.
std::vector<int> numbers = {1, 2, 3, 4, 5};
for (int n : numbers) {
    std::cout << n << " ";
}4. Smart Pointers
Introduces std::unique_ptr and std::shared_ptr to manage dynamic memory automatically, preventing memory leaks.
std::unique_ptr<int> ptr(new int(10)); // No need to delete ptr manually; it will be deleted when it goes out of scope
5. Move Semantics
Move semantics optimize performance by allowing resources to be transferred rather than copied.
std::vector<int> makeVector() {
    std::vector<int> v = {1, 2, 3};
    return v;  // Moves v rather than copying
}
std::vector<int> v = makeVector();  // Efficient move6. nullptr
Replaces NULL with nullptr to represent null pointers more safely.
int* p = nullptr; // p is a null pointer
7. constexpr
Allows for compile-time constant expressions, improving performance by performing computations at compile time.
constexpr int square(int x) {
    return x * x;
}
int arr[square(5)];  // Creates an array of size 258. std::thread
Provides a standard way to create and manage threads, enabling concurrent programming.
#include <thread>
#include <iostream>
void hello() {
    std::cout << "Hello from thread!" << std::endl;
}
int main() {
    std::thread t(hello);
    t.join();  // Wait for thread to finish
    return 0;
}9. Variadic Templates
Supports templates with a variable number of arguments, making template programming more flexible.
template<typename... Args>
void print(Args... args) {
    (std::cout << ... << args) << std::endl;  // Fold expression (C++17)
}
print(1, 2, "three", 4.0);10. Uniform Initialization
Enables a consistent syntax for initializing variables and containers.
int arr[] = {1, 2, 3};
std::vector<int> v = {1, 2, 3, 4, 5};
struct Point { int x, y; };
Point p = {1, 2};C++14
C++14 built upon the foundation of C++11, introducing several important enhancements to improve code readability, flexibility, and performance. Here are the major features with examples:
1. Generic Lambdas
C++14 allows the use of auto in lambda parameter lists, making lambdas more flexible and easier to use with generic code.
Example:
auto add = [](auto a, auto b) { return a + b; };
std::cout << add(1, 2) << std::endl; // Output: 3
std::cout << add(1.5, 2.3) << std::endl; // Output: 3.82. Variable Templates
Variable templates enable the definition of templates for variables, not just functions or classes.
Example:
template<typename T> constexpr T pi = T(3.1415926535897932385L); std::cout << pi<double> << std::endl; // Output: 3.14159 std::cout << pi<float> << std::endl; // Output: 3.14159f
3. Return Type Deduction
C++14 allows functions to deduce their return type automatically using auto.
Example:
auto add(int a, int b) {
    return a + b;
}
std::cout << add(1, 2) << std::endl; // Output: 34. std::make_unique
This utility function simplifies the creation of std::unique_ptr instances, making the code more readable and less error-prone.
Example:
#include <memory> auto ptr = std::make_unique<int>(42); std::cout << *ptr << std::endl; // Output: 42
5. Deprecated Attribute
The [[deprecated]] attribute can be used to mark functions and variables as deprecated, generating compile-time warnings when they are used.
Example:
[[deprecated("Use new_function() instead")]]
void old_function() {}
void new_function() {}
int main() {
    old_function(); // Warning: 'old_function' is deprecated: Use new_function() instead
    new_function();
}6. Binary Literals and Digit Separators
C++14 introduced binary literals prefixed with 0b or 0B and the single quotation mark as a digit separator to improve readability of large numbers.
Example:
int binary = 0b1010; // Binary literal int largeNumber = 1'000'000; // Digit separator std::cout << binary << std::endl; // Output: 10 std::cout << largeNumber << std::endl; // Output: 1000000
C++17
C++17 brought a plethora of new features and enhancements, making the language more expressive and user-friendly. Here are some of the major additions with detailed explanations and examples:
1.std::optional
std::optional is a utility that represents a value that may or may not be present. It’s useful for functions that might not return a value.
Example:
#include <optional>
#include <iostream>
std::optional<int> find_even_number(int num) {
    if (num % 2 == 0) return num;
    return std::nullopt;
}
int main() {
    auto result = find_even_number(4);
    if (result) {
        std::cout << "Even number: " << *result << "\n";
    } else {
        std::cout << "Not an even number\n";
    }
}2.std::variant
std::variant is a type-safe union, allowing a variable to hold one of several specified types.
Example:
#include <variant>
#include <iostream>
int main() {
    std::variant<int, float, std::string> my_variant;
    my_variant = 10;
    std::cout << std::get<int>(my_variant) << "\n";
    my_variant = 3.14f;
    std::cout << std::get<float>(my_variant) << "\n";
    my_variant = "Hello";
    std::cout << std::get<std::string>(my_variant) << "\n";
}3.std::any
std::any is a type-safe container for single values of any type. It’s useful when the type of the value is not known at compile time.
Example:
#include <any>
#include <iostream>
int main() {
    std::any my_any;
    my_any = 42;
    std::cout << std::any_cast<int>(my_any) << "\n";
    my_any = std::string("Hello");
    std::cout << std::any_cast<std::string>(my_any) << "\n";
}4. Structured Bindings
Structured bindings allow for unpacking tuple-like objects directly into individual variables.
Example:
#include <tuple>
#include <iostream>
std::tuple<int, float, std::string> get_data() {
    return {1, 2.3f, "test"};
}
int main() {
    auto [i, f, s] = get_data();
    std::cout << "i: " << i << ", f: " << f << ", s: " << s << "\n";
}5.if constexpr
if constexpr enables compile-time conditional compilation.
Example:
#include <iostream>
template <typename T>
void print_type_info(T value) {
    if constexpr (std::is_integral_v<T>) {
        std::cout << "Integral type\n";
    } else {
        std::cout << "Non-integral type\n";
    }
}
int main() {
    print_type_info(42);
    print_type_info(3.14);
}6. Fold Expressions
Fold expressions simplify the use of variadic templates by providing a concise syntax for operations on parameter packs.
Example:
#include <iostream>
template<typename... Args>
auto sum(Args... args) {
    return (... + args); // fold expression
}
int main() {
    std::cout << "Sum: " << sum(1, 2, 3, 4, 5) << "\n";
}7. Filesystem Library
The <filesystem> library provides facilities for performing operations on file systems and their components.
Example:
#include <filesystem>
#include <iostream>
int main() {
    std::filesystem::path p{"example.txt"};
    if (std::filesystem::exists(p)) {
        std::cout << p << " exists\n";
    } else {
        std::cout << p << " does not exist\n";
    }
}These features collectively enhance the power and flexibility of C++, making it easier to write robust, modern, and efficient code.
C++20
C++20 is a milestone in the evolution of C++, bringing a host of powerful features that enhance the language’s expressiveness, safety, and performance. Here’s a detailed look at the major additions with examples:
1. Concepts
Concepts provide a way to specify constraints on template parameters, making templates more readable and error messages more understandable.
#include <concepts>
#include <iostream>
template <typename T>
concept Integral = std::is_integral_v<T>;
template <Integral T>
T add(T a, T b) {
    return a + b;
}
int main() {
    std::cout << add(3, 4) << '\n';  // Works
    // std::cout << add(3.0, 4.0) << '\n';  // Error: double doesn't satisfy Integral
}2. Ranges
The Ranges library introduces a new way to work with sequences of data, making code more readable and expressive.
#include <ranges>
#include <vector>
#include <iostream>
int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    auto result = v | std::ranges::views::filter([](int n) { return n % 2 == 0; });
    for (int n : result) {
        std::cout << n << ' ';  // Output: 2 4
    }
}3. Coroutines
Coroutines allow for writing asynchronous code in a sequential style, simplifying the development of concurrent applications.
#include <coroutine>
#include <iostream>
struct ReturnObject {
    struct promise_type {
        ReturnObject get_return_object() { return {}; }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
        void return_void() {}
    };
};
ReturnObject foo() {
    std::cout << "Hello ";
    co_await std::suspend_always{};
    std::cout << "World\n";
}
int main() {
    auto handle = foo();
    handle.resume();
    handle.resume();
}4. Modules
Modules provide a new way to organize and import code, improving compile times and code encapsulation.
// my_module.ixx
export module my_module;
export int add(int a, int b) {
    return a + b;
}
// main.cpp
import my_module;
#include <iostream>
int main() {
    std::cout << add(3, 4) << '\n';  // Output: 7
}5. Three-way Comparison (Spaceship Operator)
The three-way comparison operator (<=>) simplifies the implementation of comparisons and provides a consistent way to handle them.
#include <compare>
#include <iostream>
struct Point {
    int x, y;
    auto operator<=>(const Point&) const = default;
};
int main() {
    Point p1{1, 2}, p2{2, 3};
    if (p1 < p2) {
        std::cout << "p1 is less than p2\n";  // Output
    }
}6. Calendar and Time Zone Library
This library provides comprehensive support for handling dates, times, and time zones.
#include <chrono>
#include <iostream>
int main() {
    using namespace std::chrono;
    auto now = system_clock::now();
    auto today = floor<days>(now);
    std::cout << "Today is: " << today.time_since_epoch().count() << " days since epoch\n";
}C++20 significantly enriches the language, making it more modern and powerful for a wide range of programming tasks. These features together improve the robustness, readability, and maintainability of C++ code.
C++23
C++23 introduces several powerful features that enhance the language’s capabilities, safety, and ease of use. Here’s a detailed look at some of the most significant additions:
1. std::expected
std::expected is a new utility for error handling, similar to std::optional but with built-in error state management.
Example:
#include <iostream>
#include <expected>
std::expected<int, std::string> divide(int a, int b) {
    if (b == 0) {
        return std::unexpected("Division by zero!");
    }
    return a / b;
}
int main() {
    auto result = divide(10, 0);
    if (!result) {
        std::cout << "Error: " << result.error() << '\n';
    } else {
        std::cout << "Result: " << *result << '\n';
    }
}2.std::mdspan
std::mdspan is a multi-dimensional array view, providing a way to describe the shape and layout of data in memory.
Example:
#include <iostream>
#include <mdspan>
int main() {
    int data[6] = {1, 2, 3, 4, 5, 6};
    std::mdspan<int, std::extents<2, 3>> mdspan(data);
    for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 3; ++j) {
            std::cout << mdspan(i, j) << ' ';
        }
        std::cout << '\n';
    }
}3. Reflection (Experimental)
C++23 introduces experimental reflection capabilities, allowing compile-time introspection of types and their properties.
Example:
#include <iostream>
#include <experimental/reflect>
struct MyStruct {
    int a;
    double b;
    void foo() {}
};
int main() {
    auto type = reflexpr(MyStruct);
    for (auto member : type.get_data_members()) {
        std::cout << "Member name: " << member.get_name() << '\n';
    }
}4.if consteval
The if consteval statement allows code to check if it is being evaluated at compile-time.
Example:
#include <iostream>
constexpr int factorial(int n) {
    if consteval {
        if (n < 0) throw "Negative input!";
    }
    return n <= 1 ? 1 : n * factorial(n - 1);
}
int main() {
    std::cout << factorial(5) << '\n'; // OK
    // std::cout << factorial(-1) << '\n'; // Compile-time error
}5.[[assume]] Attribute
The [[assume]] attribute allows developers to provide assumptions to the optimizer, improving performance by informing the compiler about invariants.
Example:
#include <iostream>
int main() {
    int x = 5;
    [[assume(x > 0)]];
    std::cout << "x is positive.\n";
}These features have significantly enhanced C++’s expressiveness, safety, and performance, keeping it a robust choice for modern software development. But how many of them have you already used?


