参考:

1 C++14 简介

什么是 C++14?

2014 年 8 月 18 日,ISO(国际标准化组织) 批准了 C++ 的新版本,称为 C++14。与增加了大量新功能的 C++11 不同,C++14 是一个相对较小更新,主要包含错误修复和一些小改进。

C++14 中的新改进

为了方便您参考,我们列出了 C++14 的主要改进。请注意,此列表并非详尽无遗,旨在重点介绍一些您感兴趣的关键改进。

1.1 函数 auto 返回类型推导

// C++11 需要指定返回类型
auto func() -> int {
    return 42;
}
 
// C++14 可以自动推导
auto func() {
    return 42;  // 推导为 int
}
 
// 递归函数也支持
auto fibonacci(int n) {
    if (n <= 1) return n;
    return fibonacci(n-1) + fibonacci(n-2);
}

1.2 通用 lambda 表达式(lambda 自动参数类型)

// C++14 lambda 参数可以使用 auto
auto lambda = [](auto x, auto y) {
    return x + y;
};
 
int result1 = lambda(1, 2);        // int + int
double result2 = lambda(1.5, 2.3); // double + double
string result3 = lambda(string("Hello"), string(" World")); // string + string

1.3 变量模板

template<typename T>
constexpr T pi = T(3.1415926535897932385);
 
// 使用
float f = pi<float>;
double d = pi<double>;
long double ld = pi<long double>;

1.4 std::make_unique

#include <memory>
 
// C++14 引入 make_unique
auto ptr = std::make_unique<int>(42);
auto arr = std::make_unique<int[]>(10);
 
// 相比 new 更安全
class Widget {
public:
    Widget(int x, double y) : x_(x), y_(y) {}
private:
    int x_;
    double y_;
};
 
auto widget = std::make_unique<Widget>(10, 3.14);

1.5 数字分隔符

// 使用单引号作为数字分隔符,提高可读性
int million = 1'000'000;
long long large = 1'234'567'890'123LL;
double pi = 3.14159'26535'89793;
int binary = 0b1010'0001'1000'0101;
int hex = 0xFF'FF'FF'FF;

1.6 二进制字面量

// C++14 引入二进制字面量
int binary1 = 0b1010;        // 10
int binary2 = 0B11110000;    // 240
int flags = 0b0001'0010'0100; // 使用分隔符提高可读性

1.7 std::integer_sequence

#include <utility>
#include <array>
 
template<typename T, T... ints>
void print_sequence(std::integer_sequence<T, ints...>) {
    ((std::cout << ints << " "), ...); // C++17 折叠表达式
}
 
// 编译时生成序列
template<size_t N>
constexpr auto make_array() {
    return std::make_integer_sequence<size_t, N>{};
}
 
// 使用
print_sequence(std::make_index_sequence<5>{}); // 0 1 2 3 4

1.8 std::exchange

详见 std::exchange

#include <utility>
 
class MyClass {
    std::unique_ptr<int> ptr_;
public:
    // 移动构造函数中的常见用法
    MyClass(MyClass&& other) noexcept 
        : ptr_(std::exchange(other.ptr_, nullptr)) {}
    
    // 重置并返回旧值
    std::unique_ptr<int> reset(std::unique_ptr<int> new_ptr) {
        return std::exchange(ptr_, std::move(new_ptr));
    }
};

2 C++17 简介

什么是 C++17?

2017 年 9 月,ISO(国际标准化组织) 批准了 C++ 的新版本,称为 C++17。C++17 包含大量新内容

C++17 中的新改进

为了方便您参考,我们列出了 C++17 的主要变更。请注意,此列表并非详尽无遗,旨在重点介绍一些您感兴趣的关键变更。

2.1 结构化绑定

#include <tuple>
#include <map>
#include <string>
 
// 元组解包
std::tuple<int, double, std::string> getTuple() {
    return {42, 3.14, "hello"};
}
 
auto [i, d, s] = getTuple();
// i = 42, d = 3.14, s = "hello"
 
// map 遍历更简洁
std::map<std::string, int> m = {{"apple", 1}, {"banana", 2}};
for (const auto& [key, value] : m) {
    std::cout << key << ": " << value << std::endl;
}
 
// 数组解包
int arr[] = {1, 2, 3};
auto [a, b, c] = arr;

2.2 if constexpr

template<typename T>
void process(T&& t) {
    if constexpr (std::is_integral_v<T>) {
        // 编译时条件,只有 T 是整数类型时才编译这部分
        std::cout << "Processing integer: " << t << std::endl;
    } else if constexpr (std::is_floating_point_v<T>) {
        std::cout << "Processing float: " << t << std::endl;
    } else {
        std::cout << "Processing other type" << std::endl;
    }
}
 
process(42);      // "Processing integer: 42"
process(3.14);    // "Processing float: 3.14"
process("hello"); // "Processing other type"

2.3 std::optional

#include <optional>
#include <string>
 
std::optional<std::string> findUser(int id) {
    if (id == 1) {
        return "Alice";
    }
    return std::nullopt; // 空值
}
 
// 使用
auto user = findUser(1);
if (user.has_value()) {
    std::cout << "Found: " << user.value() << std::endl;
}
 
// 或者更简洁
if (user) {
    std::cout << "Found: " << *user << std::endl;
}
 
// 提供默认值
std::string name = findUser(999).value_or("Unknown");

2.4 std::variant

#include <variant>
#include <string>
 
std::variant<int, double, std::string> data;
 
data = 42;
data = 3.14;
data = std::string("hello");
 
// 访问
if (std::holds_alternative<std::string>(data)) {
    std::cout << std::get<std::string>(data) << std::endl;
}
 
// 使用 visitor
std::visit([](const auto& value) {
    std::cout << "Value: " << value << std::endl;
}, data);

2.5 类模板参数推导 (CTAD)

// C++17 之前
std::pair<int, double> p1(42, 3.14);
std::vector<int> v1{1, 2, 3, 4, 5};
 
// C++17 可以推导
std::pair p2(42, 3.14);        // 推导为 pair<int, double>
std::vector v2{1, 2, 3, 4, 5}; // 推导为 vector<int>
 
// 自定义类也支持
template<typename T>
class MyClass {
public:
    MyClass(T value) : value_(value) {}
private:
    T value_;
};
 
MyClass obj(42); // 推导为 MyClass<int>

2.6 折叠表达式

// 参数包折叠
template<typename... Args>
auto sum(Args... args) {
    return (args + ...); // 右折叠: arg1 + (arg2 + (arg3 + ...))
}
 
template<typename... Args>
void print(Args... args) {
    ((std::cout << args << " "), ...); // 逗号折叠
    std::cout << std::endl;
}
 
int result = sum(1, 2, 3, 4, 5); // 15
print("Hello", "World", 123);     // "Hello World 123"

2.7 内联变量 (inline variables)

// 头文件中定义全局变量,避免重定义错误
inline int global_counter = 0;
inline std::string app_name = "MyApp";
 
// 类静态成员变量
class Config {
public:
    inline static const std::string default_path = "/etc/config";
    inline static std::vector<std::string> allowed_extensions{".txt", ".json", ".xml"};
};

2.8 constexpr if 的高级用法

template<typename Container>
void process_container(Container&& c) {
    if constexpr (std::is_same_v<std::decay_t<Container>, std::string>) {
        std::cout << "Processing string: " << c << std::endl;
    } else if constexpr (std::is_arithmetic_v<typename Container::value_type>) {
        std::cout << "Processing numeric container, sum = ";
        std::cout << std::accumulate(c.begin(), c.end(), 0) << std::endl;
    } else {
        std::cout << "Processing generic container with " << c.size() << " elements" << std::endl;
    }
}

2.9 std::any

#include <any>
#include <string>
 
void any_example() {
    std::any data;
    
    data = 42;
    data = std::string("Hello");
    data = 3.14;
    
    // 类型检查和转换
    if (data.type() == typeid(double)) {
        double value = std::any_cast<double>(data);
        std::cout << "Double value: " << value << std::endl;
    }
    
    // 安全转换
    if (auto ptr = std::any_cast<double>(&data)) {
        std::cout << "Value: " << *ptr << std::endl;
    }
}

2.10 std::string_view

#include <string_view>
 
// 避免不必要的字符串拷贝
void process_string(std::string_view sv) {
    std::cout << "Processing: " << sv << std::endl;
    // 可以对子串进行操作
    if (sv.starts_with("prefix_")) {
        sv.remove_prefix(7); // 移除前缀
    }
    if (sv.ends_with("_suffix")) {
        sv.remove_suffix(7); // 移除后缀
    }
}
 
// 可以接受各种字符串类型
std::string str = "Hello World";
const char* cstr = "Hello World";
process_string(str);   // 不会拷贝
process_string(cstr);  // 不会拷贝
process_string("Hello World"); // 字面量,不拷贝

2.11 嵌套命名空间

// C++17 简化嵌套命名空间声明
namespace company::project::module {
    void function() {
        std::cout << "Inside nested namespace" << std::endl;
    }
}
 
// 等价于:
// namespace company {
//     namespace project {
//         namespace module {
//             void function() { ... }
//         }
//     }
// }

2.12 属性 [[fallthrough]],[[nodiscard]], [[maybe_unused]]

// [[fallthrough]] - 明确表示故意落空
int process_grade(int grade) {
    switch (grade) {
    case 90 ... 100:
        std::cout << "A grade";
        [[fallthrough]]; // 明确表示故意落空到下一个case
    case 80 ... 89:
        std::cout << " - Excellent!" << std::endl;
        break;
    default:
        std::cout << "Other grade" << std::endl;
    }
    return grade;
}
 
// [[nodiscard]] - 警告忽略返回值
[[nodiscard]] int important_calculation() {
    return 42;
}
 
// [[maybe_unused]] - 抑制未使用警告
void debug_function([[maybe_unused]] int debug_level) {
#ifdef DEBUG
    std::cout << "Debug level: " << debug_level << std::endl;
#endif
    // release版本中debug_level未使用,但不会产生警告
}

3 C++20 简介

什么是 C++20?

2020 年 2 月,ISO(国际标准化组织) 批准了 C++ 的新版本,称为 C++20。C++20 包含了自 C++11 以来对该语言的最大更改。

C++20 中的新改进

为了方便您参考,我们列出了 C++20 的主要变更。请注意,此列表并非详尽无遗,旨在重点介绍一些您感兴趣的关键变更。

  • 通过自动参数缩写函数模板(11.8 - 具有多种模板类型的函数模板
  • Chrono 扩展用于日历和时区支持(尚无教程)
  • Concepts,允许您对模板参数施加约束(尚无教程)
  • Constexpr dynamic_cast 和 typeid(尚无教程)
  • Constexpr 虚函数(暂无教程)
  • Constexpr try-catch(尚无教程)
  • Constinit 关键字,用于断言变量具有静态初始化(尚无教程)
  • Coroutines 协程(暂无教程)
  • 指定初始化器(13.8——结构聚合初始化
  • 使用 consteval 关键字的立即函数(F.1 - Constexpr 函数
  • Modules,#include 的替代品(暂无教程)
  • Ranges(尚无教程)
  • std::erase(尚无教程)
  • 数组的 std::make_shared(尚无教程)
  • std::map::contains()(尚无教程)
  • std::span(尚无教程)
  • 字符串格式化库(暂无教程,请参阅 https://en.cppreference.com/w/cpp/utility/format
  • 字符串文字作为模板参数(尚无教程)
  • 使用宇宙飞船运算符 <=> 进行三向比较(尚无教程)
  • 使用作用域枚举(13.6 - 作用域枚举(枚举类)
  • Views 视图(尚无教程)

3.1 概念 (Concepts)

#include <concepts>
 
// 定义概念
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
 
template<typename T>
concept Addable = requires(T a, T b) {
    { a + b } -> std::same_as<T>;
};
 
// 使用概念约束模板
template<Numeric T>
T add(T a, T b) {
    return a + b;
}
 
// 或者使用 requires 子句
template<typename T>
requires Addable<T>
T multiply(T a, T b) {
    return a * b;
}
 
// 编译时检查
add(1, 2);      // OK
add(1.5, 2.3);  // OK
// add("hello", "world"); // 编译错误

3.2 协程 (Coroutines)

#include <coroutine>
#include <iostream>
 
// 简单的生成器
struct Generator {
    struct promise_type {
        int current_value;
        
        Generator get_return_object() {
            return Generator{std::coroutine_handle<promise_type>::from_promise(*this)};
        }
        
        std::suspend_always initial_suspend() { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        void unhandled_exception() {}
        
        std::suspend_always yield_value(int value) {
            current_value = value;
            return {};
        }
        
        void return_void() {}
    };
    
    std::coroutine_handle<promise_type> h;
    
    Generator(std::coroutine_handle<promise_type> handle) : h(handle) {}
    ~Generator() { if (h) h.destroy(); }
    
    bool next() {
        h.resume();
        return !h.done();
    }
    
    int value() {
        return h.promise().current_value;
    }
};
 
Generator counter(int start, int end) {
    for (int i = start; i <= end; ++i) {
        co_yield i;  // 协程关键字
    }
}
 
// 使用
auto gen = counter(1, 5);
while (gen.next()) {
    std::cout << gen.value() << " ";
}

3.3 模块 (Modules)

// math.cppm - 模块接口文件
export module math;
 
export namespace math {
    int add(int a, int b) {
        return a + b;
    }
    
    int multiply(int a, int b) {
        return a * b;
    }
}
 
// main.cpp - 使用模块
import math;
import <iostream>;
 
int main() {
    std::cout << math::add(2, 3) << std::endl;      // 5
    std::cout << math::multiply(4, 5) << std::endl; // 20
    return 0;
}

3.4 范围 (Ranges)

#include <ranges>
#include <vector>
#include <algorithm>
#include <iostream>
 
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
 
// 链式操作
auto result = numbers 
    | std::views::filter([](int n) { return n % 2 == 0; })  // 过滤偶数
    | std::views::transform([](int n) { return n * n; })     // 平方
    | std::views::take(3);                                   // 取前3个
 
for (int n : result) {
    std::cout << n << " "; // 4 16 36
}
 
// 范围算法
std::ranges::sort(numbers);
auto it = std::ranges::find(numbers, 5);
bool all_positive = std::ranges::all_of(numbers, [](int n) { return n > 0; });

3.5 三路比较操作符 (<=>)

#include <compare>
 
class Point {
public:
    int x, y;
    
    // 自动生成所有比较操作符
    auto operator<=>(const Point& other) const = default;
    
    // 或者自定义比较逻辑
    // std::strong_ordering operator<=>(const Point& other) const {
    //     if (auto cmp = x <=> other.x; cmp != 0) return cmp;
    //     return y <=> other.y;
    // }
};
 
Point p1{1, 2};
Point p2{1, 3};
 
bool equal = p1 == p2;     // false
bool less = p1 < p2;       // true
bool greater = p1 > p2;    // false
auto cmp = p1 <=> p2;      // std::strong_ordering::less

3.6 指定初始化器

struct Config {
    std::string host = "localhost";
    int port = 8080;
    bool ssl = false;
    int timeout = 30;
};
 
// 指定初始化,可以跳过某些字段
Config config {
    .host = "example.com",
    .port = 443,
    .ssl = true
    // timeout 使用默认值 30
};

3.7 constexpr 虚函数

class Base {
public:
    constexpr virtual ~Base() = default;
    constexpr virtual int getValue() const = 0;
};
 
class Derived : public Base {
public:
    constexpr int getValue() const override {
        return 42;
    }
};
 
// 编译时多态
constexpr int compute() {
    Derived d;
    const Base* ptr = &d;
    return ptr->getValue(); // 编译时调用虚函数
}
 
static_assert(compute() == 42);

3.8 constexpr 容器和算法

#include <vector>
#include <algorithm>
#include <array>
 
constexpr std::array<int, 5> create_and_sort() {
    std::array<int, 5> arr{5, 2, 8, 1, 9};
    std::sort(arr.begin(), arr.end());
    return arr;
}
 
constexpr auto sorted_array = create_and_sort();
// 编译时排序:{1, 2, 5, 8, 9}
 
// constexpr vector (C++20)
constexpr std::vector<int> create_vector() {
    std::vector<int> vec;
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);
    return vec;
}

3.9 字符串字面量操作符模板

template<typename CharT, CharT... chars>
constexpr auto operator""_compile_time() {
    constexpr CharT str[] = {chars..., '\0'};
    return str;
}
 
// 编译时字符串处理
constexpr auto ct_string = "Hello"_compile_time;

3.10 std::span

#include <span>
#include <vector>
#include <array>
 
// 统一的数组/容器视图
void process_data(std::span<const int> data) {
    std::cout << "Processing " << data.size() << " elements" << std::endl;
    for (int value : data) {
        std::cout << value << " ";
    }
    std::cout << std::endl;
}
 
// 可以接受各种容器类型
std::vector<int> vec{1, 2, 3, 4, 5};
std::array<int, 3> arr{6, 7, 8};
int c_array[] = {9, 10, 11};
 
process_data(vec);     // vector
process_data(arr);     // array
process_data(c_array); // C数组
process_data({1, 2, 3}); // 初始化列表

3.11 requires 表达式的高级用法

#include <concepts>
 
// 复杂的概念约束
template<typename T>
concept Container = requires(T t) {
    typename T::value_type;
    typename T::iterator;
    { t.begin() } -> std::same_as<typename T::iterator>;
    { t.end() } -> std::same_as<typename T::iterator>;
    { t.size() } -> std::convertible_to<std::size_t>;
};
 
template<typename T>
concept PrintableContainer = Container<T> && requires(typename T::value_type v) {
    std::cout << v; // 元素必须可打印
};
 
// 使用复杂概念
template<PrintableContainer T>
void print_container(const T& container) {
    for (const auto& item : container) {
        std::cout << item << " ";
    }
    std::cout << std::endl;
}

3.12 std::jthread 和协作式取消

#include <thread>
#include <stop_token>
#include <chrono>
 
void worker_function(std::stop_token stoken) {
    while (!stoken.stop_requested()) {
        // 执行工作
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        
        if (stoken.stop_requested()) {
            std::cout << "Gracefully stopping..." << std::endl;
            break;
        }
    }
}
 
void thread_example() {
    // jthread 自动加入,支持协作式取消
    std::jthread worker(worker_function);
    
    std::this_thread::sleep_for(std::chrono::seconds(1));
    
    // 请求停止
    worker.request_stop();
    
    // jthread 析构时自动join
}

3.13 std::source_location

#include <source_location>
#include <iostream>
 
void log_message(const std::string& msg, 
                const std::source_location& loc = std::source_location::current()) {
    std::cout << "[" << loc.file_name() << ":" << loc.line() << "] "
              << loc.function_name() << ": " << msg << std::endl;
}
 
void some_function() {
    log_message("Debug info"); 
    // 输出: [main.cpp:25] some_function: Debug info
}

3.14 std::format (C++20)

#include <format>
 
void formatting_examples() {
    std::string name = "Alice";
    int age = 30;
    double salary = 75000.50;
    
    // 基本格式化
    std::string msg = std::format("Hello, {}! You are {} years old.", name, age);
    
    // 数字格式化
    std::string salary_msg = std::format("Salary: ${:.2f}", salary);
    
    // 位置参数
    std::string ordered = std::format("{1} is {0} years old", age, name);
    
    // 填充和对齐
    std::string aligned = std::format("|{:>10}|{:<10}|{:^10}|", "right", "left", "center");
    
    std::cout << msg << std::endl;         // Hello, Alice! You are 30 years old.
    std::cout << salary_msg << std::endl;  // Salary: $75000.50
    std::cout << ordered << std::endl;     // Alice is 30 years old
    std::cout << aligned << std::endl;     // |     right|left      |  center  |
}

4 C++23 简介

什么是 C++23?

2023 年 2 月,ISO(国际标准化组织)批准了 C++ 的新版本,称为 C++23。

C++23 中的新改进

为了方便您参考,我们列出了 C++23 的主要变更。请注意,此列表并非详尽无遗,旨在重点介绍一些您感兴趣的关键变更。

  • Constexpr <cmath> (例如 std::abs())和 <cstdlib>6.7 — 关系运算符和浮点比较)。
  • Constexpr std::unique_ptr(尚无课程)。
  • 显式 this 参数(尚无课程)。
  • 固定大小的浮点类型(通过 <stdfloat>)(尚无课程)。
  • 格式化打印功能 std::printstd::println(暂无课程)
  • 的文字后缀 std::size_t 和相应的有符号类型(5.2——文字)。
  • 多维下标(在 第 17.13 课“多维 std::arrayoperator[] ”中提到)。
  • 多维跨度 std::mdspan17.13—多维 std::array)。
  • 预处理器指令 #elifdef#elifndef(尚无课程)。
  • 预处理器指令 #warning (尚无课程)。
  • Stacktrace 库(尚未上课)
  • 标准库模块 std(和 std.compat)(尚无课程)。
  • 静态 operator()operator[](尚未上课)。
  • std::bitset 现在完全是 constexpr。
  • std::expected(尚未上课)
  • std::ranges 算法 starts_with,,ends_withcontains 尚未上课)
  • std::string::contains 并且 std::string_view::contains(尚未上课)
  • std::to_underlying 获取枚举的底层类型(13.6——范围枚举(枚举类))。
  • std::unreachable()(尚未上课)。
  • 在常量表达式中使用未知的指针和引用(17.2——std::array 长度和索引)。

4.1 std::expected

#include <expected>
#include <string>
 
enum class ErrorCode {
    FileNotFound,
    PermissionDenied,
    NetworkError
};
 
std::expected<std::string, ErrorCode> readFile(const std::string& filename) {
    if (filename.empty()) {
        return std::unexpected(ErrorCode::FileNotFound);
    }
    
    // 模拟读取文件
    if (filename == "secret.txt") {
        return std::unexpected(ErrorCode::PermissionDenied);
    }
    
    return "File content: " + filename;
}
 
// 使用
auto result = readFile("data.txt");
if (result.has_value()) {
    std::cout << "Success: " << result.value() << std::endl;
} else {
    std::cout << "Error code: " << static_cast<int>(result.error()) << std::endl;
}
 
// 链式操作
auto processed = readFile("data.txt")
    .transform([](const std::string& content) {
        return content + " (processed)";
    })
    .or_else([](ErrorCode ec) -> std::expected<std::string, ErrorCode> {
        return "Default content";
    });

4.2 std::mdspan (多维数组视图)

#include <mdspan>
 
void matrix_example() {
    // 原始数据
    std::vector<double> data(12);
    std::iota(data.begin(), data.end(), 1.0); // 填充 1, 2, 3, ..., 12
    
    // 创建 3x4 矩阵视图
    std::mdspan matrix(data.data(), 3, 4);
    
    // 访问元素
    matrix[1, 2] = 99.0;  // 设置第1行第2列
    
    // 遍历
    for (size_t i = 0; i < matrix.extent(0); ++i) {
        for (size_t j = 0; j < matrix.extent(1); ++j) {
            std::cout << matrix[i, j] << " ";
        }
        std::cout << std::endl;
    }
}

4.3 std::print

#include <print>
#include <vector>
 
void print_examples() {
    // 格式化输出,类似 Python 的 print
    std::print("Hello, {}!\n", "World");
    std::print("Number: {}, Float: {:.2f}\n", 42, 3.14159);
    
    // 输出到文件
    std::ofstream file("output.txt");
    std::print(file, "Writing to file: {}\n", "success");
    
    // 复杂格式化
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    std::print("Numbers: {}\n", numbers);  // 需要格式化器支持
}

4.4 if consteval

#include <type_traits>
 
consteval bool is_constant_evaluated() {
    return true;
}
 
constexpr bool is_runtime() {
    return false;
}
 
constexpr int getValue() {
    if consteval {
        // 编译时执行
        return 42;
    } else {
        // 运行时执行
        return 24;
    }
}
 
// 使用
constexpr int compile_time = getValue();  // 42
int runtime = getValue();                 // 24 (如果不是在常量表达式中调用)

4.5 多维下标操作符

class Matrix {
private:
    std::vector<std::vector<int>> data;
    
public:
    Matrix(size_t rows, size_t cols) : data(rows, std::vector<int>(cols)) {}
    
    // C++23 多维下标操作符
    int& operator[](size_t row, size_t col) {
        return data[row][col];
    }
    
    const int& operator[](size_t row, size_t col) const {
        return data[row][col];
    }
};
 
// 使用
Matrix matrix(3, 4);
matrix[1, 2] = 42;        // 直接使用多个索引
int value = matrix[1, 2]; // 获取值

4.6 std::flat_map 和 std::flat_set

#include <flat_map>
#include <flat_set>
 
void flat_containers_example() {
    // 基于连续内存的关联容器,查找性能更好
    std::flat_map<std::string, int> scores;
    scores["Alice"] = 95;
    scores["Bob"] = 87;
    scores["Charlie"] = 92;
    
    // 遍历是有序的,且内存局部性更好
    for (const auto& [name, score] : scores) {
        std::cout << name << ": " << score << std::endl;
    }
    
    std::flat_set<int> unique_numbers{3, 1, 4, 1, 5, 9, 2, 6};
    // 自动去重并排序:{1, 2, 3, 4, 5, 6, 9}
}

4.7 constexpr 增强

#include <vector>
#include <algorithm>
 
// C++23 允许更多标准库函数在编译时使用
constexpr std::vector<int> create_sorted_vector() {
    std::vector<int> vec{3, 1, 4, 1, 5, 9, 2, 6};
    std::ranges::sort(vec);  // C++23 可以在 constexpr 中使用
    return vec;
}
 
constexpr auto sorted = create_sorted_vector();
// 编译时就计算出排序结果

4.8 std::optional 增强

#include <optional>
 
// std::optional 的 monadic 操作
std::optional<std::string> get_user(int id) {
    if (id == 1) return "Alice";
    return std::nullopt;
}
 
std::optional<std::string> to_upper(const std::string& s) {
    if (s.empty()) return std::nullopt;
    std::string result = s;
    std::transform(result.begin(), result.end(), result.begin(), ::toupper);
    return result;
}
 
void optional_monadic() {
    auto result = get_user(1)
        .and_then(to_upper)  // 如果有值则调用函数
        .or_else([]() -> std::optional<std::string> { 
            return "DEFAULT"; 
        });
    
    // 结果: "ALICE" 或 "DEFAULT"
    std::cout << result.value_or("UNKNOWN") << std::endl;
}

4.9 范围构造函数和 std::ranges::to

#include <ranges>
#include <vector>
#include <set>
 
void ranges_to_example() {
    std::vector<int> numbers{1, 2, 3, 4, 5, 2, 3, 1};
    
    // 转换为不同容器类型
    auto unique_sorted = numbers 
        | std::views::filter([](int n) { return n > 2; })
        | std::ranges::to<std::set>(); // C++23 ranges::to
    
    // 结果: {3, 4, 5} (自动去重排序)
    for (int n : unique_sorted) {
        std::cout << n << " ";
    }
}

4.10 std::generator (协程生成器)

#include <generator>
 
// C++23 标准协程生成器
std::generator<int> fibonacci() {
    int a = 0, b = 1;
    while (true) {
        co_yield a;
        auto temp = a;
        a = b;
        b = temp + b;
    }
}
 
void generator_example() {
    auto fib = fibonacci();
    auto it = fib.begin();
    
    for (int i = 0; i < 10; ++i) {
        std::cout << *it << " ";
        ++it;
    }
    // 输出: 0 1 1 2 3 5 8 13 21 34
}

4.11 std::stacktrace

#include <stacktrace>
#include <iostream>
 
void function_c() {
    auto trace = std::stacktrace::current();
    std::cout << "Stack trace from function_c:" << std::endl;
    std::cout << trace << std::endl;
}
 
void function_b() {
    function_c();
}
 
void function_a() {
    function_b();
}
 
// 调用 function_a() 会打印完整的调用栈

4.12 std::unreachable

#include <utility>
 
int categorize_grade(int grade) {
    if (grade >= 90) return 1;
    if (grade >= 80) return 2;
    if (grade >= 70) return 3;
    if (grade >= 60) return 4;
    if (grade >= 0) return 5;
    
    // 告诉编译器这里永远不会到达,允许更好的优化
    std::unreachable();
}

4.13 auto(x) 和 decay-copy

template<typename T>
void process(T&& value) {
    // 强制拷贝,移除引用和cv限定符
    auto copy = auto(value);  // C++23 decay-copy
    
    // 等价于更冗长的写法:
    // auto copy = std::decay_t<T>(std::forward<T>(value));
    
    // 可以安全地异步使用copy,不担心悬空引用
    std::thread([copy = std::move(copy)] {
        // 使用copy...
    }).detach();
}

4.14 std::byteswap

#include <bit>
 
void endian_operations() {
    uint32_t value = 0x12345678;
    
    // 字节序转换
    uint32_t swapped = std::byteswap(value);
    // swapped = 0x78563412
    
    std::cout << std::hex << "Original: " << value << std::endl;
    std::cout << std::hex << "Swapped: " << swapped << std::endl;
}

4.15 Deducing this (显式对象参数)

class MyClass {
public:
    // C++23 deducing this - 显式对象参数
    template<typename Self>
    auto&& get_value(this Self&& self) {
        return std::forward<Self>(self).value_;
    }
    
    // 避免了写4个重载版本:
    // const T& get_value() const &;
    // T& get_value() &;
    // const T&& get_value() const &&;
    // T&& get_value() &&;
    
private:
    std::string value_ = "Hello";
};

4.16 std::move_only_function

#include <functional>
 
void move_only_function_example() {
    // 可以存储只能移动的可调用对象
    std::unique_ptr<int> ptr = std::make_unique<int>(42);
    
    std::move_only_function<int()> func = [ptr = std::move(ptr)]() mutable {
        return *ptr;
    };
    
    // std::function 无法存储上面的lambda,但move_only_function可以
    int result = func();  // 42
}

此文件夹下有1条笔记。