0% found this document useful (0 votes)
24 views

more cpp23 lib examples

Cpp23 lib examples

Uploaded by

mohamed.nar
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
24 views

more cpp23 lib examples

Cpp23 lib examples

Uploaded by

mohamed.nar
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 6

Seven More Examples for C++23 Library

Changes
C++23 gives us plenty of cool features. Below you can find more examples that extend my blog
article - C++23 Library Features and Reference Cards - C++ Stories.

1. std::ranges::to<>
The ranges::to<> feature allows you to easily convert ranges into containers:

#include <ranges>
#include <vector>
#include <iostream>
#include <string>
#include <unordered_map>
#include <map>

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

std::unordered_map<int, std::string> number_to_text = {


{1, "one"}, {2, "two"}, {3, "three"}, {4, "four"}, {5, "five"},
{6, "six"}, {7, "seven"}, {8, "eight"}, {9, "nine"}, {10, "ten"}
};

auto even_numbers = numbers


| std::views::filter([](int n) { return n % 2 == 0; })
| std::ranges::to<std::vector>();

auto text_numbers_map = even_numbers


| std::views::transform([&number_to_text](int n) {
return std::pair{n, number_to_text.contains(n) ?
number_to_text[n] : "unknown" };
})
| std::ranges::to<std::map>();

std::cout << "Even numbers: ";


for (int n : even_numbers) std::cout << n << " ";
std::cout << "\nTextual numbers:\n";
for (const auto& [k, v] : text_numbers_map)
std::cout << k << " -> " << v << '\n';
}

Run @Compiler Explorer

As you can see, there's no issue in creating not only vectors but maps as well.
2. std::print and std::println
The new formatted output library simplifies printing. Here's an example that demonstrates
alignment, formatting, and table creation:

#include <print>
#include <unordered_map>
#include <string>
#include <numeric>

int main() {
// Store the data in an unordered_map (country -> size in km²)
std::unordered_map<std::string, double> country_sizes = {
{"USA", 9833517},
{"Canada", 9984670},
{"Australia", 7692024},
{"China", 9596961},
{"Poland", 312696}
};

constexpr double KM_TO_MI = 0.386102; // Conversion factor

const double total_km = std::accumulate(country_sizes.begin(),


country_sizes.end(), 0.0,
[](double sum, const auto& entry) { return
sum + entry.second; });
const double total_mi = total_km * KM_TO_MI;

// Table headers
std::println("{:<15} | {:>15} | {:>15}", "Country", "Size (km²)", "Size
(mi²)");
std::println("{:-<15}-+-{:-<15}-+-{:-<15}", "", "", ""); // Separator line

// Table rows
for (const auto& [country, size_km] : country_sizes) {
double size_mi = size_km * KM_TO_MI; // Compute size in square miles
dynamically
std::println("{:<15} | {:>15.0f} | {:>15.2f}", country, size_km,
size_mi);
}

// Footer
std::println("{:-<15}-+-{:-<15}-+-{:-<15}", "", "", ""); // Separator line
std::println("{:<15} | {:>15.0f} | {:>15.2f}", "Total", total_km, total_mi);
}

Run @Compiler Explorer

Example output:
Country | Size (km²) | Size (mi²)
----------------+-----------------+----------------
Poland | 312696 | 120732.55
China | 9596961 | 3705405.84
Australia | 7692024 | 2969905.85
Canada | 9984670 | 3855101.06
USA | 9833517 | 3796740.58
----------------+-----------------+----------------
Total | 37419868 | 14447885.87

3. std::optional Monadic Operations


The new and_then , transform , and or_else functions make working with std::optional
more expressive. Here's an example that chains operations to process user input.

#include <optional>
#include <iostream>
#include <string>
#include <algorithm>

std::optional<std::string> get_user_input() {
std::string input;
std::cout << "Enter your name: ";
std::getline(std::cin, input);
if (input.empty()) return std::nullopt;
return input;
}

int main() {
auto result = get_user_input()
.transform([](std::string name) {
std::transform(name.begin(), name.end(), name.begin(), ::toupper);
return name;
})
.and_then([](std::string name) {
if (name == "ADMIN") return std::optional<std::string>("Welcome,
Admin!");
return std::optional<std::string>("Hello, " + name + "!");
})
.or_else([] {
return std::optional<std::string>("No input provided.");
});

std::cout << *result << "\n";


}

Experiment at @Compiler Explorer


4. std::generator
The std::generator feature simplifies creating lazy sequences. Here's an example of reading line
by line from a file:

#include <generator>
#include <fstream>
#include <iostream>
#include <string>

// Coroutine to read lines from a file


std::generator<std::string> read_lines(const std::string& filename) {
std::ifstream file(filename);
std::string line;
while (std::getline(file, line)) {
co_yield line;
}
}

int main() {
const std::string temp_filename = "temp_file.txt";
{
std::ofstream temp_file(temp_filename);
temp_file << "Line 1: Hello, World!\n";
temp_file << "Line 2: This is a test.\n";
temp_file << "Line 3: C++ coroutines are cool!\n";
}

for (const auto& line : read_lines(temp_filename)) {


std::cout << line << std::endl;
}
}

See @Compiler Explorer

5. std::mdspan
The std::mdspan feature is useful for multidimensional data. Here's an example of matrix
multiplication.

#include <https://raw.githubusercontent.com/kokkos/mdspan/single-
header/mdspan.hpp>
#include <vector>
#include <print>

void multiply_matrices(std::mdspan<int, std::dextents<size_t, 2>> A,


std::mdspan<int, std::dextents<size_t, 2>> B,
std::mdspan<int, std::dextents<size_t, 2>> C) {
for (size_t i = 0; i < A.extent(0); ++i) {
for (size_t j = 0; j < B.extent(1); ++j) {
C[i, j] = 0;
std::print("{}{}: ", i, j);
for (size_t k = 0; k < A.extent(1); ++k) {
std::print("+= {} x {}, ", A[i, k], B[k, j]);
C[i, j] += A[i, k] * B[k, j];
}
std::println();
}
}
}

int main() {
std::vector<int> A_data = {1, 2, 3, 4, 5, 6};
std::vector<int> B_data = {1, 2, 3, 4, 5, 6};
std::vector<int> C_data(4);

auto A = std::mdspan(A_data.data(), 2, 3);


auto B = std::mdspan(B_data.data(), 3, 2);
auto C = std::mdspan(C_data.data(), 2, 2);

multiply_matrices(A, B, C);

for (size_t i = 0; i < C.extent(0); ++i) {


for (size_t j = 0; j < C.extent(1); ++j) {
std::print("{} ", C[i, j]);
}
std::println();
}
}

Experiment @Compiler Explorer

6. cartesian_product , enumerate , and zip


#include <ranges>
#include <print>
#include <vector>

int main() {
std::vector<int> range1 = {1, 2, 3};
std::vector<char> range2 = {'A', 'B', 'C'};

auto product = std::views::cartesian_product(range1, range2);


std::println("Cartesian Product:");
for (const auto& [a, b] : product)
std::println("({}, {})", a, b);

auto enumerated = std::views::enumerate(range1);


std::println("\nEnumerated Range:");
for (const auto& [index, value] : enumerated)
std::println("Index: {}, Value: {}", index, value);

auto zipped = std::views::zip(range1, range2);


std::println("\nZipped Ranges:");
for (const auto& [a, b] : zipped)
std::println("({}, {})", a, b);
}
Run @Compiler Explorer

7. chunk , slide and stride


#include <ranges>
#include <print>
#include <vector>

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

// Chunk: divide the range into groups of 3


auto chunks = std::views::chunk(numbers, 3);
std::println("Chunks of 3:");
for (const auto& chunk : chunks) {
for (int n : chunk)
std::print("{} ", n);
std::println("");
}

// Slide: create overlapping subranges of size 3


auto sliding = std::views::slide(numbers, 3);
std::println("\nSliding Window of 3:");
for (const auto& window : sliding) {
for (int n : window)
std::print("{} ", n);
std::println("");
}

// Stride: skip every 2 elements


auto strided = std::views::stride(numbers, 2);
std::println("\nStrided Range (step 2):");
for (int n : strided)
std::print("{} ", n);
}

Run @Compiler Explorer

You might also like