DEV Community

Cover image for Top C++20/23 Features
Santhosh Balasa
Santhosh Balasa

Posted on • Edited on

11 1 1 1 1

Top C++20/23 Features

1) Coroutines:

Coroutines simplify asynchronous and concurrent programming by allowing functions to be suspended and resumed. They use co_yield, co_await, and co_return keywords.

Example:

#include <iostream>
#include <coroutine>

std::coroutine<int> generator() {
    for (int i = 0; i < 5; ++i) {
        co_yield I;
    }
}

int main() {
    for (int value : generator()) {
        std::cout << value << '\n';
    }
}
Enter fullscreen mode Exit fullscreen mode

2) Ranges:

Ranges provide a more expressive way to work with sequences of values. The new views namespace contains adaptors that allow for lazy evaluation, improving performance and code readability.

Example:

#include <iostream>
#include <ranges>
#include <vector>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    // Filter even numbers and double their value.
    auto transformed_numbers = numbers | std::views::filter([](int n) { return n % 2 == 0; })
                                       | std::views::transform([](int n) { return n * 2; });

    for (int number : transformed_numbers) {
        std::cout << number << '\n';
    }
}
Enter fullscreen mode Exit fullscreen mode

3) Pattern Matching:

Pattern matching allows for more concise and expressive ways to deal with complex data structures. The inspect keyword is introduced for this purpose.

Example:

#include <iostream>
#include <variant>

using VarType = std::variant<int, double, std::string>;

void print_value(const VarType& var) {
    inspect (var) {
        int x: std::cout << "Integer: " << x << '\n';
        double y: std::cout << "Double: " << y << '\n';
        std::string s: std::cout << "String: " << s << '\n';
    }
}

int main() {
    VarType a = 42;
    VarType b = 3.14;
    VarType c = "Hello, World!";

    print_value(a);
    print_value(b);
    print_value(c);
}
Enter fullscreen mode Exit fullscreen mode

4) Static Exceptions:

Static exceptions are a new way to handle errors without the overhead of traditional C++ exceptions. They use the throws keyword to declare that a function may return an error.

Example:

#include <iostream>
#include <stdexcept>
#include <string>

std::expected<int, std::string> divide(int a, int b) throws {
    if (b == 0) {
        return std::unexpected("division by zero");
    }

    return a / b;
}

int main() {
    auto result = divide(10, 0);
    if (result) {
        std::cout << "Result: " << *result << '\n';
    } else {
        std::cout << "Error: " << result.error() << '\n';
    }
}
Enter fullscreen mode Exit fullscreen mode

5) Concepts and Constraints:

Concepts allow you to specify constraints on template parameters, making the code more readable and producing better error messages during compilation.

Example:

#include <iostream>
#include <concepts>

template<typename T>
concept Numeric = std::is_arithmetic_v<T>;

template<Numeric T>
T add(T a, T b) {
    return a + b;
}

int main() {
    int result = add(1, 2); // This will compile
    // std::string error = add("Hello", "World"); // This will produce a compilation error
    std::cout << result << '\n';
}
Enter fullscreen mode Exit fullscreen mode

6) constinit:

The constinit keyword guarantees that a variable will be initialized during compile time, improving performance by avoiding the need for dynamic initialization.

Example:

#include <iostream>

constinit int compile_time_value = 42;

int main() {
    std::cout << "Value: " << compile_time_value << '\n';
}
Enter fullscreen mode Exit fullscreen mode

7) to_underlying:

The std::to_underlying function simplifies converting an enumeration to its underlying type.

Example:

#include <iostream>
#include <utility>

enum class Color : int {
    Red = 1,
    Green = 2,
    Blue = 3
};

int main() {
    Color c = Color::Red;
    int color_code = std::to_underlying(c);
    std::cout << "Color code: " << color_code << '\n';
}
Enter fullscreen mode Exit fullscreen mode

8) source_location:

The std::source_location class provides a simple way to obtain information about the source code location where it's used, such as file name, line number, and function name.

Example:

#include <iostream>
#include <source_location>

void print_location(const std::source_location& location = std::source_location::current()) {
    std::cout << "File: " << location.file_name() << '\n'
              << "Line: " << location.line() << '\n'
              << "Function: " << location.function_name() << '\n';
}

int main() {
    print_location();
}
Enter fullscreen mode Exit fullscreen mode

9) flat_set and flat_map:

These new containers store elements in a sorted, contiguous memory region, offering better cache locality and faster lookup times compared to std::set and std::map.

Example:

#include <iostream>
#include <flat_set>
#include <string>

int main() {
    std::flat_set<std::string> names = {"Alice", "Bob", "Eve"};

    auto it = names.find("Bob");
    if (it != names.end()) {
        std::cout << "Found: " << *it << '\n';
    }
}
Enter fullscreen mode Exit fullscreen mode

10) simd:

The new std::simd library provides a way to use SIMD (Single Instruction, Multiple Data) operations in C++ programs, allowing for better performance on supported hardware.

Example:

#include <iostream>
#include <algorithm>
#include <execution>
#include <simd>
#include <vector>

int main() {
    std::vector<float> a = {1.0f, 2.0f, 3.0f, 4.0f};
    std::vector<float> b = {5.0f, 6.0f, 7.0f, 8.0f};
    std::vector<float> c(a.size());

    std::transform(std::execution::simd, a.begin(), a.end(), b.begin(), c.begin(), std::plus<float>());

    for (float value : c) {
        std::cout << value << '\n';
    }
}
Enter fullscreen mode Exit fullscreen mode

11) span improvements:

std::span is a non-owning, bounds-safe view over a contiguous sequence of objects. In C++23, new features have been added, such as the ssize function, which returns the size of the span as a signed integer.

Example:

#include <iostream>
#include <span>
#include <vector>

void print_positive_size(const std::span<int>& sp) {
    std::cout << "Size: " << std::ssize(sp) << '\n';
}

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    std::span<int> num_span(numbers);

    print_positive_size(num_span);
}
Enter fullscreen mode Exit fullscreen mode

12) make_shared:

C++23 adds support for creating std::shared_ptr instances for arrays using std::make_shared.

Example:

#include <iostream>
#include <memory>

int main() {
    auto array_ptr = std::make_shared<int[]>(5);

    for (int i = 0; i < 5; ++i) {
        array_ptr[i] = i;
    }

    for (int i = 0; i < 5; ++i) {
        std::cout << array_ptr[i] << '\n';
    }
}
Enter fullscreen mode Exit fullscreen mode

13) contains:

C++23 adds std::contains to various standard library containers, simplifying the process of checking whether a container contains a specific value.

Example:

#include <iostream>
#include <unordered_set>

int main() {
    std::unordered_set<int> numbers = {1, 2, 3, 4, 5};

    if (numbers.contains(3)) {
        std::cout << "3 is in the set." << '\n';
    }
}
Enter fullscreen mode Exit fullscreen mode

14) erase_if:

C++23 introduces std::erase_if, a utility function to remove elements from a container based on a specific condition.

Example:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    std::erase_if(numbers, [](int n) { return n % 2 == 0; });

    for (int number : numbers) {
        std::cout << number << ' ';
    }
}
Enter fullscreen mode Exit fullscreen mode

15) chrono improvements:

C++23 introduces new functions and features to the std::chrono library, such as calendar and timezone support.

Example:

#include <iostream>
#include <chrono>
#include <format>

int main() {
    using namespace std::chrono;

    // Get the current time in the system's local timezone
    zoned_time local_time{current_zone(), system_clock::now()};

    // Output the formatted local time
    std::cout << "Local time: " << std::format("{:%Y-%m-%d %H:%M:%S}", local_time) << '\n';
}
Enter fullscreen mode Exit fullscreen mode

16) Lambda improvements:

C++23 introduces improvements to lambda expressions, such as making them more expressive and easier to use.

Example:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    // A lambda with a template parameter
    auto print_value = []<typename T>(const T& value) {
        std::cout << value << ' ';
    };

    std::for_each(numbers.begin(), numbers.end(), print_value);
}
Enter fullscreen mode Exit fullscreen mode

17) net:

C++23 introduces a new networking library, std::net, which provides support for sockets, address resolution, and more.

Example:

#include <iostream>
#include <net>

int main() {
    std::net::ip::tcp::iostream stream("www.example.com", "http");
    if (!stream) {
        std::cerr << "Error: " << stream.error().message() << '\n';
        return 1;
    }

    stream << "GET / HTTP/1.1\r\n"
           << "Host: www.example.com\r\n"
           << "Connection: close\r\n\r\n";
    stream.flush();

    std::string line;
    while (std::getline(stream, line)) {
        std::cout << line << '\n';
    }
}
Enter fullscreen mode Exit fullscreen mode

18) New algorithms in algorithm:

C++23 adds new algorithms to the std::algorithm library, such as shift_left and shift_right, which shift elements within a range.

Example:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    std::shift_left(numbers.begin(), numbers.end(), 2);

    for (int number : numbers) {
        std::cout << number << ' ';
    }
}
Enter fullscreen mode Exit fullscreen mode

19) identity:

The std::identity function object is introduced in C++23, which can be useful in generic programming as a simple pass-through function.

Example:

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    std::transform(numbers.begin(), numbers.end(), numbers.begin(), std::identity{});

    for (int number : numbers) {
        std::cout << number << ' ';
    }
}
Enter fullscreen mode Exit fullscreen mode

20) bulk_execute:

C++23 adds new functions to the std::execution library, such as std::execution::bulk_execute, which allows you to run a function multiple times concurrently.

Example:

#include <iostream>
#include <execution>
#include <thread>

void print_hello(size_t index) {
    std::cout << "Hello from task " << index << '\n';
}

int main() {
    std::execution::bulk_execute(std::execution::par, print_hello, 10);
}
Enter fullscreen mode Exit fullscreen mode

21) counted_iterator:

C++23 introduces std::counted_iterator, which is useful for creating an iterator that keeps track of a remaining count.

Example:

#include <iostream>
#include <iterator>
#include <vector>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    auto start = std::counted_iterator(numbers.begin(), 5);
    auto end = std::default_sentinel;

    for (auto it = start; it != end; ++it) {
        std::cout << *it << ' ';
    }
}
Enter fullscreen mode Exit fullscreen mode

22) default_initializable:

C++23 introduces the std::default_initializable concept, which helps to ensure that a type can be default-initialized.

Example:

#include <iostream>
#include <concepts>

template <std::default_initializable T>
T get_default() {
    return T{};
}

int main() {
    int default_int = get_default<int>();
    std::cout << "Default int: " << default_int << '\n';
}
Enter fullscreen mode Exit fullscreen mode

23) starts_with and ends_with:

C++23 adds starts_with and ends_with member functions to std::basic_string, making it easier to check if a string starts or ends with a specific substring or character.

Example:

#include <iostream>
#include <string>

int main() {
    std::string greeting = "Hello, world!";

    if (greeting.starts_with("Hello")) {
        std::cout << "The greeting starts with 'Hello'." << '\n';
    }

    if (greeting.ends_with('!')) {
        std::cout << "The greeting ends with an exclamation mark." << '\n';
    }
}
Enter fullscreen mode Exit fullscreen mode

24) is_scoped_enum:

C++23 adds the std::is_scoped_enum type trait, which helps determine if a given type is a scoped enumeration (i.e., an enum class).

Example:

#include <iostream>
#include <type_traits>

enum class ScopedEnum { A, B, C };
enum UnscopedEnum { X, Y, Z };

int main() {
    std::cout << std::boolalpha
              << "ScopedEnum is scoped: " << std::is_scoped_enum_v<ScopedEnum> << '\n'
              << "UnscopedEnum is scoped: " << std::is_scoped_enum_v<UnscopedEnum> << '\n';
}
Enter fullscreen mode Exit fullscreen mode

25) chunk:

C++23 introduces std::views::chunk, which allows you to create a view that groups elements in a range into subranges of a specified size.

Example:

#include <iostream>
#include <vector>
#include <ranges>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto chunked_view = numbers | std::views::chunk(3);

    for (const auto& chunk : chunked_view) {
        for (int number : chunk) {
            std::cout << number << ' ';
        }
        std::cout << '\n';
    }
}
Enter fullscreen mode Exit fullscreen mode

26) unwrap_reference:

C++23 introduces std::unwrap_reference, a utility to unwrap reference_wrapper instances and leave other types unchanged.

Example:

#include <iostream>
#include <functional>
#include <type_traits>

int main() {
    int value = 42;
    std::reference_wrapper<int> ref_wrapper(value);

    // Unwrap reference_wrapper
    auto& unwrapped_ref = std::unwrap_reference(ref_wrapper);

    // Modify the original value through the unwrapped reference
    unwrapped_ref = 55;

    std::cout << "Original value: " << value << '\n';
}
Enter fullscreen mode Exit fullscreen mode

27) copyable and movable:

C++23 introduces the std::copyable and std::movable concepts, which help ensure that a type is copyable or movable, respectively.

Example:

#include <iostream>
#include <concepts>

template <std::copyable T>
void process_copyable(const T& obj) {
    // Process obj
}

template <std::movable T>
void process_movable(T&& obj) {
    // Process obj
}

int main() {
    int value = 42;
    process_copyable(value); // OK, int is copyable
    process_movable(std::move(value)); // OK, int is movable
}
Enter fullscreen mode Exit fullscreen mode

28) polymorphic_allocator improvements:

C++23 enhances std::polymorphic_allocator with additional features, such as support for array allocations.

Example:

#include <iostream>
#include <memory_resource>
#include <vector>

int main() {
    std::pmr::unsynchronized_pool_resource pool;
    std::pmr::polymorphic_allocator<int> alloc(&pool);

    std::pmr::vector<int> numbers(alloc);
    numbers.reserve(10);
    for (int i = 1; i <= 10; ++i) {
        numbers.push_back(i);
    }

    for (int number : numbers) {
        std::cout << number << ' ';
    }
}
Enter fullscreen mode Exit fullscreen mode

29) dynamic_extent:

C++23 introduces std::dynamic_extent, which is a constant that represents a dynamic extent for span and mdspan.

Example:

#include <iostream>
#include <span>
#include <vector>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    std::span<int, std::dynamic_extent> dynamic_span(numbers);

    for (int number : dynamic_span) {
        std::cout << number << ' ';
    }
}
Enter fullscreen mode Exit fullscreen mode

30) to_underlying:

C++23 introduces std::to_underlying, a utility function that makes it easier to convert an enumeration value to its underlying integral type.

Example:

#include <iostream>
#include <type_traits>

enum class Color : int { Red, Green, Blue };

int main() {
    Color color = Color::Red;

    auto underlying_value = std::to_underlying(color);

    std::cout << "Color::Red has an underlying value of: " << underlying_value << '\n';
}
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
sandordargo profile image
Sandor Dargo
Comment hidden by post author
Collapse
 
snawaz profile image
Sarfaraz Nawaz
Comment hidden by post author

Some comments have been hidden by the post's author - find out more