参考:
1 C++14 简介
什么是 C++14?
2014 年 8 月 18 日,ISO(国际标准化组织) 批准了 C++ 的新版本,称为 C++14。与增加了大量新功能的 C++11 不同,C++14 是一个相对较小更新,主要包含错误修复和一些小改进。
C++14 中的新改进
为了方便您参考,我们列出了 C++14 的主要改进。请注意,此列表并非详尽无遗,旨在重点介绍一些您感兴趣的关键改进。
- 聚合成员初始化(13.7——结构、成员和成员选择简介)
- 二进制文字(5.3 — 数字系统(十进制、二进制、十六进制和八进制))
deprecated属性(尚无教程)- 数字分隔符(5.3 — 数字系统(十进制、二进制、十六进制和八进制))
- 函数 auto 返回类型推导(10.8——使用 auto 关键字进行对象的类型推导)
- 通用 lambda 表达式(20.6 — lambda 表达式(匿名函数)简介)
- 放宽 constexpr 函数(F.1 — Constexpr 函数)
- 变量模板(尚无教程)
- std::make_unique(22.5—std::unique_ptr)
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 + string1.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 41.8 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 的主要变更。请注意,此列表并非详尽无遗,旨在重点介绍一些您感兴趣的关键变更。
- 类模板实参推导(CTAD)(13.14 — 类模板实参推导(CTAD)和推导指南)
- 在编译时解析的 if 语句(8.4 — Constexpr if 语句)
- if 语句和 switch 语句中的初始化器(在 13.y — 使用语言参考 中提到)
- 内联变量(7.10——跨多个文件共享全局常量(使用内联变量))
- 折叠表达式(尚无教程)
- 某些情况下强制复制省略(在 14.15 — 类初始化和复制省略中 提到)
- 嵌套命名空间现在可以定义为命名空间 X::Y (7.2 — 用户定义的命名空间和范围解析运算符)
- 删除 std::auto_ptr 和一些其他弃用的类型
- static_assert 不再需要诊断文本消息参数(9.6 - Assert 和 static_assert)
- std::any(尚无教程)
- std::byte(尚无教程)
- std::filesystem(尚无教程)
- std::optional(12.15—std::optional)
- std::shared_ptr 现在可以管理 C 样式数组(但 std::make_shared 还不能创建它们)(22.6 — std::shared_ptr)
- std::size(11.2——数组(第二部分))
- std::string_view (5.8 — std::string_view 简介)
- 结构化绑定声明(尚无教程)
- 三字母组合已被删除
- 现在可以在模板模板参数中使用 typename(而不是 class)
- UTF-8(u8)字符文字(尚无教程)
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::less3.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::print和std::println(暂无课程) - 的文字后缀
std::size_t和相应的有符号类型(5.2——文字)。 - 多维下标(在 第 17.13 课“多维 std::array
operator[]”中提到)。 - 多维跨度
std::mdspan(17.13—多维 std::array)。 - 预处理器指令
#elifdef和#elifndef(尚无课程)。 - 预处理器指令
#warning(尚无课程)。 - Stacktrace 库(尚未上课)
- 标准库模块
std(和std.compat)(尚无课程)。 - 静态
operator()且operator[](尚未上课)。 std::bitset现在完全是 constexpr。std::expected(尚未上课)std::ranges算法starts_with,,ends_with(contains尚未上课)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
}