本章目标:std::print/println、std::expected、std::mdspan(了解)、 std::flat_map(了解)、deducing this(了解)、 其他实用小特性。C++23 是"补全体验"的版本, 没有颠覆性大特性,但每天都在改善你的代码。
#include <print>
std::println("你好,{}!", name);
std::print("不换行输出");
自 C++23 起,新代码的输出一律用 print/println。
#include <expected>
enum class Err { BadInput, OutOfRange };
std::expected<int, Err> parse_int(std::string_view s) {
int v = 0;
// ... 解析逻辑 ...
if (解析失败) return std::unexpected(Err::BadInput);
return v;
}
auto r = parse_int("42");
if (r) {
std::println("值是 {}", *r); // 正常分支
} else {
std::println("出错了:{}", r.error()); // 错误分支
}
// 也可以变换:
auto doubled = r.transform([](int x){ return x * 2; }); // 成功则变换
auto handled = r.value_or(-1); // 失败给默认值
人话:expected<T, E> = "要么是 T,要么是 E(错误)"。 和 optional 的区别:optional 只知道"有没有", expected 还告诉你"为什么没有"。
适用场景:函数可能失败,且调用方通常需要处理错误。 (比异常快、比错误码安全、可组合。详见第十五章。)
#include <mdspan>
std::vector<double> data(24);
std::mdspan matrix(data.data(), 4, 6); // 把一维数据当 4x6 矩阵
matrix[2, 3] = 1.5; // 下标语法
知道即可,用到再学。
#include <flat_map>
std::flat_map<std::string, int> m;
m["a"] = 1; // 用法和 map 几乎一样
和 map 的区别:
查找 O(log n) 但缓存命中率高,小数据量大胜出
结论:数据量小(几百上千)且读多写少 → flat_map 更快。 游戏开发常用它。
以前成员函数里的 this 是固定类型:
struct Widget {
void foo() const; // this 是 const Widget*
};
复制粘贴 const/& 版本非常烦人。
C++23:给 this 起名字,让它自动推断:
struct Widget {
void foo(this auto&& self) { // 自动匹配 const/&
// self 就是对象自己,类型自动
}
};
好处:
知道这是"给 this 起名"就行,高级用法按需学。
for (auto [x, y] : std::views::zip(v1, v2)) { ... }
for (auto [i, x] : std::views::enumerate(v)) { ... }
你的 Termux 版暂时没有,用 accumulate 替代,见下节注释)
#include <print>
#include <ranges>
#include <string>
#include <vector>
int main() {
std::vector<std::string> names{"bob", "alice", "carol", "dave"};
// 打印带编号的名字(enumerate 是 C++23,
// 你的 Termux libc++ 暂时没有,用下标循环代替,效果一样)
for (std::size_t i = 0; i < names.size(); ++i) {
std::println("{}. {}", i + 1, names[i]);
}
// 过滤 + 变换 + 收集成新 vector
// (std::ranges::to<vector> 也暂缺,手动构造即可)
std::vector<std::string> long_names;
for (const auto& s : names
| std::views::filter([](const std::string& s) {
return s.size() >= 4;
})) {
long_names.push_back(s);
}
std::println("有 {} 个长名字", long_names.size());
}
注:enumerate / fold_left / ranges::to 是 C++23 新增, 新版 libc++(clang 19+ 自带)才完整。你的 Termux 环境 libc++ 版本略旧,本书示例已全部换成等价写法, 等系统更新后可直接换回新写法(语法见 13.6)。
C++17 时代:optional、结构化绑定、filesystem、if constexpr C++20 时代:ranges 管道、concepts、三路比较、span、chrono C++23 时代:print、expected、fold、zip/enumerate、to<vector>
现代 C++(17+)写代码的固定姿势:
练习题
(等价于 views::zip 的效果)。