1/*
2 * Modern C++ Features Demo (C++17/C++20)
3 *
4 * Demonstrates:
5 * - Structured bindings (C++17)
6 * - std::optional, std::variant, std::any
7 * - if constexpr
8 * - Fold expressions
9 * - std::filesystem
10 * - C++20 concepts
11 *
12 * Compile: g++ -std=c++20 -Wall -Wextra 01_modern_cpp.cpp -o modern_cpp
13 */
14
15#include <iostream>
16#include <optional>
17#include <variant>
18#include <any>
19#include <vector>
20#include <map>
21#include <filesystem>
22#include <string>
23#include <concepts>
24
25namespace fs = std::filesystem;
26
27// ============ C++20 Concepts ============
28template<typename T>
29concept Numeric = std::integral<T> || std::floating_point<T>;
30
31template<Numeric T>
32T add(T a, T b) {
33 return a + b;
34}
35
36// ============ Structured Bindings ============
37void demo_structured_bindings() {
38 std::cout << "\n=== Structured Bindings (C++17) ===\n";
39
40 // Tuple decomposition
41 auto tuple = std::make_tuple(42, "hello", 3.14);
42 auto [num, str, pi] = tuple;
43 std::cout << "Tuple: " << num << ", " << str << ", " << pi << "\n";
44
45 // Map iteration
46 std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}};
47 for (const auto& [name, score] : scores) {
48 std::cout << name << ": " << score << "\n";
49 }
50
51 // Pair decomposition
52 std::pair<int, std::string> pair = {100, "perfect"};
53 auto [value, description] = pair;
54 std::cout << "Pair: " << value << " = " << description << "\n";
55}
56
57// ============ std::optional ============
58std::optional<int> safe_divide(int a, int b) {
59 if (b == 0) return std::nullopt;
60 return a / b;
61}
62
63void demo_optional() {
64 std::cout << "\n=== std::optional ===\n";
65
66 auto result1 = safe_divide(10, 2);
67 if (result1.has_value()) {
68 std::cout << "10 / 2 = " << result1.value() << "\n";
69 }
70
71 auto result2 = safe_divide(10, 0);
72 std::cout << "10 / 0 = " << result2.value_or(-1) << " (using default)\n";
73
74 // Optional chaining with transform (C++23 style shown with manual check)
75 std::optional<std::string> name = "Alice";
76 if (name) {
77 std::cout << "Name length: " << name->length() << "\n";
78 }
79}
80
81// ============ std::variant ============
82void demo_variant() {
83 std::cout << "\n=== std::variant ===\n";
84
85 std::variant<int, double, std::string> var;
86
87 var = 42;
88 std::cout << "Variant holds int: " << std::get<int>(var) << "\n";
89
90 var = 3.14;
91 std::cout << "Variant holds double: " << std::get<double>(var) << "\n";
92
93 var = "hello";
94 std::cout << "Variant holds string: " << std::get<std::string>(var) << "\n";
95
96 // Visitor pattern
97 std::visit([](auto&& arg) {
98 using T = std::decay_t<decltype(arg)>;
99 if constexpr (std::is_same_v<T, int>)
100 std::cout << "Visiting int: " << arg << "\n";
101 else if constexpr (std::is_same_v<T, double>)
102 std::cout << "Visiting double: " << arg << "\n";
103 else if constexpr (std::is_same_v<T, std::string>)
104 std::cout << "Visiting string: " << arg << "\n";
105 }, var);
106}
107
108// ============ std::any ============
109void demo_any() {
110 std::cout << "\n=== std::any ===\n";
111
112 std::any a = 42;
113 std::cout << "Any holds: " << std::any_cast<int>(a) << "\n";
114
115 a = 3.14;
116 std::cout << "Any holds: " << std::any_cast<double>(a) << "\n";
117
118 a = std::string("hello");
119 std::cout << "Any holds: " << std::any_cast<std::string>(a) << "\n";
120
121 if (a.has_value()) {
122 std::cout << "Any has a value of type: " << a.type().name() << "\n";
123 }
124}
125
126// ============ if constexpr ============
127template<typename T>
128void print_type(T value) {
129 if constexpr (std::is_integral_v<T>) {
130 std::cout << "Integer: " << value << "\n";
131 } else if constexpr (std::is_floating_point_v<T>) {
132 std::cout << "Float: " << value << "\n";
133 } else {
134 std::cout << "Other: " << value << "\n";
135 }
136}
137
138void demo_if_constexpr() {
139 std::cout << "\n=== if constexpr ===\n";
140 print_type(42);
141 print_type(3.14);
142 print_type("hello");
143}
144
145// ============ Fold Expressions ============
146template<typename... Args>
147auto sum(Args... args) {
148 return (args + ...); // Unary right fold
149}
150
151template<typename... Args>
152void print_all(Args... args) {
153 ((std::cout << args << " "), ...); // Binary left fold
154 std::cout << "\n";
155}
156
157void demo_fold_expressions() {
158 std::cout << "\n=== Fold Expressions ===\n";
159 std::cout << "Sum: " << sum(1, 2, 3, 4, 5) << "\n";
160 std::cout << "Print all: ";
161 print_all(1, "hello", 3.14, "world");
162}
163
164// ============ std::filesystem ============
165void demo_filesystem() {
166 std::cout << "\n=== std::filesystem ===\n";
167
168 fs::path current = fs::current_path();
169 std::cout << "Current directory: " << current << "\n";
170
171 // Create temporary directory and file
172 fs::path temp_dir = fs::temp_directory_path() / "cpp_demo";
173 if (!fs::exists(temp_dir)) {
174 fs::create_directory(temp_dir);
175 std::cout << "Created: " << temp_dir << "\n";
176 }
177
178 fs::path temp_file = temp_dir / "test.txt";
179 std::cout << "File exists: " << fs::exists(temp_file) << "\n";
180 std::cout << "Is directory: " << fs::is_directory(temp_dir) << "\n";
181
182 // Cleanup
183 if (fs::exists(temp_dir)) {
184 fs::remove_all(temp_dir);
185 }
186}
187
188// ============ C++20 Concepts Example ============
189void demo_concepts() {
190 std::cout << "\n=== C++20 Concepts ===\n";
191 std::cout << "add(10, 20) = " << add(10, 20) << "\n";
192 std::cout << "add(3.5, 1.5) = " << add(3.5, 1.5) << "\n";
193 // add("hello", "world"); // Compile error: doesn't satisfy Numeric
194}
195
196// ============ Main ============
197int main() {
198 std::cout << "Modern C++ Features Demo\n";
199 std::cout << "========================\n";
200
201 demo_structured_bindings();
202 demo_optional();
203 demo_variant();
204 demo_any();
205 demo_if_constexpr();
206 demo_fold_expressions();
207 demo_filesystem();
208 demo_concepts();
209
210 std::cout << "\nAll demos completed!\n";
211 return 0;
212}