cpp
examples
examples.cpp⚙️cpp
/**
* Modern C++ Features - Examples (C++17/20/23)
*
* Compile:
* C++17: g++ -std=c++17 -Wall examples.cpp -o examples
* C++20: g++ -std=c++20 -Wall examples.cpp -o examples
* C++23: g++ -std=c++23 -Wall examples.cpp -o examples
*/
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <memory>
#include <optional>
#include <variant>
#include <any>
#include <string_view>
#include <algorithm>
#include <functional>
#include <numeric>
#include <array>
#include <type_traits>
// C++20 headers (uncomment if compiler supports)
// #include <ranges>
// #include <concepts>
// #include <span>
// #include <format>
// #include <compare>
// C++23 headers (uncomment if compiler supports)
// #include <expected>
// #include <print>
using namespace std;
// ============================================================
// SECTION 1: AUTO AND TYPE INFERENCE
// ============================================================
auto add(int a, int b) {
return a + b;
}
void demoAuto() {
cout << "--- Auto and Type Inference ---\n" << endl;
auto x = 42;
auto y = 3.14;
auto s = string("Hello");
auto v = vector<int>{1, 2, 3};
cout << " x (int): " << x << endl;
cout << " y (double): " << y << endl;
cout << " s (string): " << s << endl;
cout << " v (vector): ";
for (auto n : v) cout << n << " ";
cout << endl;
cout << " add(1, 2) = " << add(1, 2) << endl;
}
// ============================================================
// SECTION 2: SMART POINTERS
// ============================================================
class Resource {
string name;
public:
Resource(const string& n) : name(n) {
cout << " Resource created: " << name << endl;
}
~Resource() {
cout << " Resource destroyed: " << name << endl;
}
void use() { cout << " Using: " << name << endl; }
};
void demoSmartPointers() {
cout << "\n--- Smart Pointers ---\n" << endl;
// unique_ptr
cout << " unique_ptr:" << endl;
{
auto p1 = make_unique<Resource>("Unique1");
p1->use();
// Transfer ownership
auto p2 = move(p1);
cout << " p1 is " << (p1 ? "valid" : "null") << endl;
p2->use();
}
// shared_ptr
cout << "\n shared_ptr:" << endl;
{
auto p1 = make_shared<Resource>("Shared1");
cout << " Use count: " << p1.use_count() << endl;
{
auto p2 = p1;
cout << " Use count (after copy): " << p1.use_count() << endl;
}
cout << " Use count (after p2 gone): " << p1.use_count() << endl;
}
// weak_ptr
cout << "\n weak_ptr:" << endl;
weak_ptr<Resource> weak;
{
auto shared = make_shared<Resource>("Weak-test");
weak = shared;
if (auto locked = weak.lock()) {
locked->use();
}
}
cout << " weak expired: " << boolalpha << weak.expired() << endl;
}
// ============================================================
// SECTION 3: LAMBDA EXPRESSIONS
// ============================================================
void demoLambdas() {
cout << "\n--- Lambda Expressions ---\n" << endl;
// Basic lambda
auto add = [](int a, int b) { return a + b; };
cout << " add(3, 4) = " << add(3, 4) << endl;
// Capture by value
int x = 10;
auto addX = [x](int a) { return a + x; };
cout << " addX(5) = " << addX(5) << endl;
// Capture by reference
int counter = 0;
auto increment = [&counter]() { return ++counter; };
cout << " increment(): " << increment() << ", "
<< increment() << ", " << increment() << endl;
// Generic lambda (C++14)
auto print = [](auto x) { cout << " print: " << x << endl; };
print(42);
print("hello");
print(3.14);
// Lambda with algorithm
vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6};
sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
cout << " Sorted desc: ";
for (int n : v) cout << n << " ";
cout << endl;
// Mutable lambda
int count = 0;
auto mutableLambda = [count]() mutable { return ++count; };
cout << " Mutable lambda: " << mutableLambda() << ", "
<< mutableLambda() << " (original count still: " << count << ")" << endl;
// Init capture (C++14)
auto ptr = make_unique<int>(100);
auto initCapture = [p = move(ptr)]() { return *p; };
cout << " Init capture (moved unique_ptr): " << initCapture() << endl;
}
// ============================================================
// SECTION 4: MOVE SEMANTICS
// ============================================================
class Movable {
vector<int> data;
public:
Movable() : data(1000, 42) {
cout << " Constructed" << endl;
}
Movable(const Movable& other) : data(other.data) {
cout << " Copy constructed" << endl;
}
Movable(Movable&& other) noexcept : data(move(other.data)) {
cout << " Move constructed" << endl;
}
size_t size() const { return data.size(); }
};
void demoMoveSemantics() {
cout << "\n--- Move Semantics ---\n" << endl;
cout << " Creating m1:" << endl;
Movable m1;
cout << " m1 size: " << m1.size() << endl;
cout << "\n Copying m1 to m2:" << endl;
Movable m2 = m1;
cout << " m1 size: " << m1.size() << endl;
cout << " m2 size: " << m2.size() << endl;
cout << "\n Moving m1 to m3:" << endl;
Movable m3 = move(m1);
cout << " m1 size: " << m1.size() << " (moved-from)" << endl;
cout << " m3 size: " << m3.size() << endl;
}
// ============================================================
// SECTION 5: STRUCTURED BINDINGS
// ============================================================
struct Point { int x, y; };
pair<int, string> getData() {
return {42, "answer"};
}
void demoStructuredBindings() {
cout << "\n--- Structured Bindings (C++17) ---\n" << endl;
// Pair
auto [num, text] = getData();
cout << " Pair: " << num << ", " << text << endl;
// Struct
Point p = {10, 20};
auto [x, y] = p;
cout << " Struct: x=" << x << ", y=" << y << endl;
// Array
int arr[] = {1, 2, 3};
auto [a, b, c] = arr;
cout << " Array: " << a << ", " << b << ", " << c << endl;
// Map iteration
map<string, int> m = {{"one", 1}, {"two", 2}, {"three", 3}};
cout << " Map: ";
for (const auto& [key, value] : m) {
cout << key << "=" << value << " ";
}
cout << endl;
}
// ============================================================
// SECTION 6: OPTIONAL
// ============================================================
optional<int> findValue(const vector<int>& v, int target) {
auto it = find(v.begin(), v.end(), target);
if (it != v.end()) return *it;
return nullopt;
}
void demoOptional() {
cout << "\n--- Optional (C++17) ---\n" << endl;
vector<int> v = {1, 2, 3, 4, 5};
auto found = findValue(v, 3);
if (found) {
cout << " Found: " << *found << endl;
}
auto notFound = findValue(v, 10);
cout << " Not found, default: " << notFound.value_or(-1) << endl;
// Optional with has_value
optional<string> name = "Alice";
if (name.has_value()) {
cout << " Name: " << name.value() << endl;
}
name = nullopt;
cout << " Name now: " << name.value_or("(none)") << endl;
}
// ============================================================
// SECTION 7: VARIANT
// ============================================================
void demoVariant() {
cout << "\n--- Variant (C++17) ---\n" << endl;
variant<int, double, string> v;
v = 42;
cout << " As int: " << get<int>(v) << endl;
v = 3.14;
cout << " As double: " << get<double>(v) << endl;
v = "hello";
cout << " As string: " << get<string>(v) << endl;
// Visit pattern
v = 100;
visit([](auto&& arg) {
using T = decay_t<decltype(arg)>;
if constexpr (is_same_v<T, int>)
cout << " Visit int: " << arg << endl;
else if constexpr (is_same_v<T, double>)
cout << " Visit double: " << arg << endl;
else
cout << " Visit string: " << arg << endl;
}, v);
// Check type
cout << " Holds int: " << boolalpha << holds_alternative<int>(v) << endl;
}
// ============================================================
// SECTION 8: STRING_VIEW
// ============================================================
void printSV(string_view sv) {
cout << " string_view: " << sv << " (length: " << sv.length() << ")" << endl;
}
void demoStringView() {
cout << "\n--- String View (C++17) ---\n" << endl;
// From literal
printSV("Hello from literal");
// From string
string s = "Hello from string";
printSV(s);
// Substring (no allocation)
string_view sv = "Hello, World!";
cout << " Substr: " << sv.substr(0, 5) << endl;
// Efficient comparisons
string_view sv1 = "test";
string_view sv2 = "test";
cout << " Equal: " << boolalpha << (sv1 == sv2) << endl;
}
// ============================================================
// SECTION 9: CONSTEXPR
// ============================================================
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
constexpr int fib(int n) {
if (n <= 1) return n;
return fib(n-1) + fib(n-2);
}
void demoConstexpr() {
cout << "\n--- Constexpr ---\n" << endl;
constexpr int fact5 = factorial(5);
constexpr int fib10 = fib(10);
cout << " factorial(5) = " << fact5 << " (compile-time)" << endl;
cout << " fib(10) = " << fib10 << " (compile-time)" << endl;
// if constexpr
auto describe = [](auto x) {
if constexpr (is_integral_v<decltype(x)>) {
cout << " Integral: " << x << endl;
} else if constexpr (is_floating_point_v<decltype(x)>) {
cout << " Floating: " << x << endl;
} else {
cout << " Other: " << x << endl;
}
};
describe(42);
describe(3.14);
describe("hello");
}
// ============================================================
// SECTION 10: CONCEPTS (C++20) - Simulated without <concepts>
// ============================================================
// Manual concept-like constraint (works in C++17)
template<typename T>
constexpr bool is_numeric_v = is_arithmetic_v<T>;
// Simulating concept behavior with enable_if
template<typename T, enable_if_t<is_numeric_v<T>, int> = 0>
T constrained_add(T a, T b) {
return a + b;
}
void demoConcepts() {
cout << "\n--- Concepts (C++20 Feature) ---\n" << endl;
cout << " Simulated concept constraint:" << endl;
cout << " constrained_add(3, 4) = " << constrained_add(3, 4) << endl;
cout << " constrained_add(1.5, 2.5) = " << constrained_add(1.5, 2.5) << endl;
// constrained_add("a", "b"); // Would fail - string is not numeric
cout << "\n With C++20 concepts, you can write:" << endl;
cout << " template<Numeric T>" << endl;
cout << " T add(T a, T b) { return a + b; }" << endl;
// Full C++20 example (commented for C++17 compatibility):
/*
#include <concepts>
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
template<Numeric T>
T add(T a, T b) { return a + b; }
// Using requires clause
template<typename T>
requires Numeric<T>
T multiply(T a, T b) { return a * b; }
// Abbreviated function template
void print(Printable auto value) {
std::cout << value << std::endl;
}
*/
}
// ============================================================
// SECTION 11: RANGES (C++20) - Manual implementation
// ============================================================
void demoRanges() {
cout << "\n--- Ranges (C++20 Feature) ---\n" << endl;
vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Manual pipeline simulation (C++17)
cout << " Original: ";
for (int x : v) cout << x << " ";
cout << endl;
// Filter even numbers and square them (manual)
vector<int> filtered;
copy_if(v.begin(), v.end(), back_inserter(filtered),
[](int n) { return n % 2 == 0; });
vector<int> transformed;
transform(filtered.begin(), filtered.end(), back_inserter(transformed),
[](int n) { return n * n; });
cout << " Filter even, then square (manual): ";
for (int x : transformed) cout << x << " ";
cout << endl;
cout << "\n With C++20 ranges, you can write:" << endl;
cout << " auto result = v" << endl;
cout << " | views::filter([](int n) { return n % 2 == 0; })" << endl;
cout << " | views::transform([](int n) { return n * n; });" << endl;
// Full C++20 example (commented for C++17 compatibility):
/*
#include <ranges>
auto result = v
| std::views::filter([](int n) { return n % 2 == 0; })
| std::views::transform([](int n) { return n * n; });
for (int x : result) {
std::cout << x << " "; // 4 16 36 64 100
}
*/
}
// ============================================================
// SECTION 12: SPAN (C++20) - Simulated
// ============================================================
// Simple span-like class for C++17
template<typename T>
class SimpleSpan {
T* data_;
size_t size_;
public:
SimpleSpan(T* ptr, size_t sz) : data_(ptr), size_(sz) {}
template<size_t N>
SimpleSpan(T (&arr)[N]) : data_(arr), size_(N) {}
SimpleSpan(vector<T>& v) : data_(v.data()), size_(v.size()) {}
T* begin() { return data_; }
T* end() { return data_ + size_; }
size_t size() const { return size_; }
T& operator[](size_t i) { return data_[i]; }
};
void process(SimpleSpan<int> data) {
cout << " Processing span of " << data.size() << " elements: ";
for (int& x : data) {
cout << x << " ";
}
cout << endl;
}
void demoSpan() {
cout << "\n--- Span (C++20 Feature) ---\n" << endl;
// Works with C-style arrays
int arr[] = {1, 2, 3, 4, 5};
process(SimpleSpan<int>(arr));
// Works with vectors
vector<int> vec = {10, 20, 30};
process(SimpleSpan<int>(vec));
cout << "\n With C++20 std::span:" << endl;
cout << " void process(std::span<int> data) { ... }" << endl;
cout << " process(arr); // Works with any contiguous container" << endl;
// Full C++20 example:
/*
#include <span>
void process(std::span<int> data) {
for (int& x : data) {
x *= 2;
}
}
int arr[] = {1, 2, 3, 4, 5};
process(arr); // Modifies array in place
std::vector<int> vec = {1, 2, 3};
process(vec); // Works with vector too
*/
}
// ============================================================
// SECTION 13: THREE-WAY COMPARISON (C++20) - Simulated
// ============================================================
struct Version {
int major, minor, patch;
// C++17 style - need all comparison operators
bool operator==(const Version& other) const {
return major == other.major && minor == other.minor && patch == other.patch;
}
bool operator<(const Version& other) const {
if (major != other.major) return major < other.major;
if (minor != other.minor) return minor < other.minor;
return patch < other.patch;
}
bool operator>(const Version& other) const { return other < *this; }
bool operator<=(const Version& other) const { return !(other < *this); }
bool operator>=(const Version& other) const { return !(*this < other); }
bool operator!=(const Version& other) const { return !(*this == other); }
};
void demoThreeWayComparison() {
cout << "\n--- Three-Way Comparison (C++20 Spaceship Operator) ---\n" << endl;
Version v1{1, 2, 3};
Version v2{1, 3, 0};
cout << " v1 = 1.2.3, v2 = 1.3.0" << endl;
cout << " v1 < v2: " << boolalpha << (v1 < v2) << endl;
cout << " v1 == v2: " << (v1 == v2) << endl;
cout << " v1 >= v2: " << (v1 >= v2) << endl;
cout << "\n With C++20 spaceship operator:" << endl;
cout << " struct Version {" << endl;
cout << " int major, minor, patch;" << endl;
cout << " auto operator<=>(const Version&) const = default;" << endl;
cout << " };" << endl;
cout << " // Generates all 6 comparison operators!" << endl;
// Full C++20 example:
/*
#include <compare>
struct Version {
int major, minor, patch;
auto operator<=>(const Version&) const = default;
};
Version v1{1, 2, 3}, v2{1, 3, 0};
auto result = v1 <=> v2; // std::strong_ordering::less
*/
}
// ============================================================
// SECTION 14: FORMAT (C++20) - Simulated with printf style
// ============================================================
void demoFormat() {
cout << "\n--- std::format (C++20 Feature) ---\n" << endl;
// C++17 - using stringstream or printf
cout << " C++17 style (stringstream):" << endl;
int x = 42;
double pi = 3.14159;
string name = "World";
// Manual formatting
cout << " Hello, " << name << "! x = " << x << ", pi = " << pi << endl;
cout << "\n With C++20 std::format:" << endl;
cout << " std::format(\"Hello, {}! x = {}, pi = {:.2f}\", name, x, pi)" << endl;
cout << " // Output: Hello, World! x = 42, pi = 3.14" << endl;
cout << "\n Format specifiers:" << endl;
cout << " {:d} - decimal, {:x} - hex, {:b} - binary" << endl;
cout << " {:>10} - right align, {:.2f} - 2 decimals" << endl;
// Full C++20 example:
/*
#include <format>
std::string s = std::format("Hello, {}!", "World");
std::string n = std::format("{:>10}", 42); // " 42"
std::string h = std::format("{:#x}", 255); // "0xff"
std::string f = std::format("{:.2f}", 3.14159); // "3.14"
// C++23 adds std::print
std::print("Value: {}\n", 42);
std::println("Line with newline: {}", x);
*/
}
// ============================================================
// SECTION 15: EXPECTED (C++23) - Simulated
// ============================================================
// Simple expected-like class for C++17
template<typename T, typename E>
class SimpleExpected {
variant<T, E> data_;
bool hasValue_;
public:
SimpleExpected(const T& value) : data_(value), hasValue_(true) {}
SimpleExpected(E error) : data_(error), hasValue_(false) {}
bool has_value() const { return hasValue_; }
operator bool() const { return hasValue_; }
T& value() { return get<T>(data_); }
const T& value() const { return get<T>(data_); }
E& error() { return get<E>(data_); }
const E& error() const { return get<E>(data_); }
T value_or(const T& defaultVal) const {
return hasValue_ ? get<T>(data_) : defaultVal;
}
};
enum class ParseError { InvalidFormat, OutOfRange, Empty };
string to_string(ParseError e) {
switch (e) {
case ParseError::InvalidFormat: return "InvalidFormat";
case ParseError::OutOfRange: return "OutOfRange";
case ParseError::Empty: return "Empty";
}
return "Unknown";
}
SimpleExpected<int, ParseError> parse_int(const string& s) {
if (s.empty()) {
return ParseError::Empty;
}
try {
size_t pos;
int value = stoi(s, &pos);
if (pos != s.length()) {
return ParseError::InvalidFormat;
}
return value;
} catch (const invalid_argument&) {
return ParseError::InvalidFormat;
} catch (const out_of_range&) {
return ParseError::OutOfRange;
}
}
void demoExpected() {
cout << "\n--- std::expected (C++23 Feature) ---\n" << endl;
auto result1 = parse_int("42");
if (result1) {
cout << " parse_int(\"42\") = " << result1.value() << endl;
}
auto result2 = parse_int("abc");
if (!result2) {
cout << " parse_int(\"abc\") error: " << to_string(result2.error()) << endl;
}
auto result3 = parse_int("");
cout << " parse_int(\"\").value_or(-1) = " << result3.value_or(-1) << endl;
cout << "\n With C++23 std::expected:" << endl;
cout << " std::expected<int, ParseError> parse(const string& s);" << endl;
cout << " auto result = parse(\"42\");" << endl;
cout << " if (result) use(*result);" << endl;
cout << " else handle(result.error());" << endl;
// Full C++23 example:
/*
#include <expected>
std::expected<int, ParseError> parse(const std::string& s) {
if (s.empty()) return std::unexpected(ParseError::Empty);
// ...
return value;
}
// Monadic operations
auto result = parse("42")
.and_then([](int x) -> std::expected<int, ParseError> {
return x * 2;
})
.transform([](int x) { return x + 1; })
.or_else([](ParseError e) -> std::expected<int, ParseError> {
return 0; // Default on error
});
*/
}
// ============================================================
// MAIN
// ============================================================
int main() {
cout << "╔══════════════════════════════════════════════════════════════╗" << endl;
cout << "║ MODERN C++ FEATURES - EXAMPLES (C++17/20/23) ║" << endl;
cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
demoAuto();
demoSmartPointers();
demoLambdas();
demoMoveSemantics();
demoStructuredBindings();
demoOptional();
demoVariant();
demoStringView();
demoConstexpr();
demoConcepts();
demoRanges();
demoSpan();
demoThreeWayComparison();
demoFormat();
demoExpected();
cout << "\n═══════════════════════════════════════════════════════════════" << endl;
cout << "Note: Some features require C++20 or C++23 compiler support." << endl;
cout << "Compile with: g++ -std=c++20 examples.cpp -o examples" << endl;
cout << "=== Complete ===" << endl;
return 0;
}