C++17 - 重大更新
C++17:重大更新
C++17 带来了许多重要的新特性,显著提升了 C++ 的表达力和安全性。
结构化绑定
// 解构 pair
std::pair<int, std::string> p{42, "hello"};
auto [id, name] = p;
// 解构 tuple
std::tuple<int, double, std::string> t{1, 3.14, "world"};
auto [x, y, z] = t;
// 解构数组
int arr[3] = {1, 2, 3};
auto [a, b, c] = arr;
// 解构结构体
struct Point {
int x;
int y;
};
Point pt{10, 20};
auto [px, py] = pt;
// 在范围 for 循环中使用
std::map<std::string, int> m{{"a", 1}, {"b", 2}};
for (const auto& [key, value] : m) {
std::cout << key << ": " << value << "\n";
}if 和 switch 初始化语句
// 传统方式
std::map<int, std::string> m;
auto it = m.find(42);
if (it != m.end()) {
// 使用 it
}
// C++17 方式
if (auto it = m.find(42); it != m.end()) {
// 使用 it
}
// 配合结构化绑定
std::map<int, std::string> m{{1, "one"}, {2, "two"}};
if (auto [it, inserted] = m.emplace(3, "three"); inserted) {
std::cout << "Inserted: " << it->second << "\n";
}
// switch 初始化语句
switch (auto it = m.find(42); auto result = it->second) {
case "found":
break;
}constexpr if
template<typename T>
auto getValue(T t) {
if constexpr (std::is_pointer_v<T>) {
return *t;
} else {
return t;
}
}
int x = 42;
std::cout << getValue(x) << "\n"; // 42
std::cout << getValue(&x) << "\n"; // 42折叠表达式
// 参数包展开
template<typename... Args>
auto sum(Args... args) {
return (args + ...); // 右折叠
}
// 使用
int total = sum(1, 2, 3, 4, 5); // 15
// 左折叠
template<typename... Args>
auto printAll(Args... args) {
(std::cout << ... << args) << "\n";
}
printAll(1, " ", 2, " ", 3); // 1 2 3
// 空参数包
template<typename... Args>
void log(Args... args) {
((std::cout << args << "\n"), ...);
}内联变量
// 头文件中定义静态成员变量
struct MyClass {
static inline int value = 42; // C++17
static inline std::vector<int> data = {1, 2, 3};
};
// 全局变量
inline constexpr int MAX_SIZE = 1000;
// 不再需要在 .cpp 文件中定义类模板参数推导(CTAD)
std::pair p{42, "hello"}; // std::pair<int, const char*>
std::tuple t{1, 2.0, "three"}; // std::tuple<int, double, const char*>
// 推导指引
template<typename T>
struct MyContainer {
MyContainer(T val) : value_(val) {}
T value_;
};
MyContainer c{42}; // MyContainer<int>
// 容器推导
std::vector v{1, 2, 3}; // std::vector<int>嵌套命名空间
// C++17 之前
namespace outer::inner {
void func() {}
}
// 等同于
namespace outer {
namespace inner {
void func() {}
}
}属性改进
// [[nodiscard]]:忽略返回值会警告
[[nodiscard]] int compute() {
return 42;
}
// compute(); // 警告:返回值被忽略
// [[maybe_unused]]:抑制未使用警告
[[maybe_unused]] int x = 42;
// [[fallthrough]]:显式表示 switch 穿透
switch (value) {
case 1:
doSomething();
[[fallthrough]];
case 2:
doSomethingElse();
break;
}
// [[nodiscard("reason")]] 自定义消息
[[nodiscard("Connection must be closed")]]
Connection connect();UTF-8 字符字面量
// UTF-8 字符字面量
char8_t c1 = u8'A'; // UTF-8 编码
// UTF-8 字符串字面量
auto str = u8"Hello, 世界!"; // const char8_t*
// Unicode 编码
char16_t c2 = u'汉'; // UTF-16
char32_t c3 = U'中'; // UTF-32std::optional
#include <optional>
std::optional<int> divide(int a, int b) {
if (b == 0) {
return std::nullopt; // 表示无值
}
return a / b;
}
auto result = divide(10, 2);
if (result) {
std::cout << *result << "\n"; // 5
}
// 使用 value_or 提供默认值
int value = divide(10, 0).value_or(-1); // -1
// 直接构造
std::optional<std::string> opt("hello");std::variant
#include <variant>
std::variant<int, double, std::string> var;
var = 42;
std::cout << std::get<int>(var) << "\n"; // 42
// 使用 std::visit
auto visitor = [](auto&& arg) {
std::cout << arg << "\n";
};
std::visit(visitor, var);
// 使用 std::holds_alternative 检查类型
if (std::holds_alternative<int>(var)) {
std::cout << "Contains int\n";
}
// 获取索引
std::cout << var.index() << "\n"; // 0std::any
#include <any>
std::any a = 42;
a = 3.14;
a = std::string("hello");
// 检查类型
if (a.type() == typeid(std::string)) {
std::cout << std::any_cast<std::string>(a) << "\n";
}
// 使用 std::any_cast
try {
int value = std::any_cast<int>(a); // 抛出异常
} catch (const std::bad_any_cast& e) {
std::cout << "Bad cast: " << e.what() << "\n";
}std::string_view
#include <string_view>
// 避免字符串拷贝
void printString(std::string_view sv) {
std::cout << sv << "\n";
}
std::string str = "hello";
const char* cstr = "world";
printString(str); // OK
printString(cstr); // OK
printString("test"); // OK
// 子串操作
std::string_view sv = "Hello, World!";
std::cout << sv.substr(0, 5) << "\n"; // Hello
std::cout << sv.starts_with("Hello") << "\n"; // truestd::byte
#include <cstddef>
// 字节类型,用于访问原始内存
std::byte b{42};
std::byte data[4];
data[0] = std::byte{0x12};
data[1] = std::byte{0x34};
// 转换为整数
int value = std::to_integer<int>(data[0]); // 18
// 内存操作
std::memset(data, std::byte{0}, sizeof(data));std::invoke
#include <functional>
// 调用函数指针
int add(int a, int b) { return a + b; }
int result = std::invoke(add, 3, 4); // 7
// 调用成员函数
struct Calculator {
int multiply(int a, int b) { return a * b; }
};
Calculator calc;
int product = std::invoke(&Calculator::multiply, calc, 3, 4); // 12
// 调用 lambda
auto lambda = [](int a, int b) { return a * b; };
int lambdaResult = std::invoke(lambda, 5, 6); // 30std::apply
#include <tuple>
int add(int a, int b, int c) { return a + b + c; }
auto t = std::make_tuple(1, 2, 3);
int result = std::apply(add, t); // 6
// 访问 tuple 元素
std::apply([](auto&... args) {
((std::cout << args << "\n"), ...);
}, t);std::make_from_tuple
#include <tuple>
struct Point {
int x;
int y;
int z;
};
auto t = std::make_tuple(1, 2, 3);
Point p = std::make_from_tuple<Point>(t); // Point{1, 2, 3}std::clamp
#include <algorithm>
int value = 75;
int minVal = 0;
int maxVal = 100;
int clamped = std::clamp(value, minVal, maxVal); // 75
int clamped2 = std::clamp(-10, minVal, maxVal); // 0
int clamped3 = std::clamp(150, minVal, maxVal); // 100
// 带比较函数
auto clamped4 = std::clamp(value, minVal, maxVal, std::greater<int>());std::reduce/std::transform_reduce
#include <numeric>
#include <execution>
std::vector<int> vec = {1, 2, 3, 4, 5};
// 并行归约
int sum = std::reduce(std::execution::par, vec.begin(), vec.end());
// 先转换后归约
auto squaredSum = std::transform_reduce(
std::execution::par,
vec.begin(), vec.end(),
0LL,
std::plus<>{},
[](int x) { return x * x; }
); // 55 (1+4+9+16+25)std::filesystem
#include <filesystem>
namespace fs = std::filesystem;
// 创建目录
fs::create_directory("test");
fs::create_directories("a/b/c"); // 递归创建
// 遍历目录
for (const auto& entry : fs::directory_iterator(".")) {
std::cout << entry.path() << "\n";
std::cout << "Is file: " << entry.is_regular_file() << "\n";
}
// 检查文件
if (fs::exists("file.txt")) {
std::cout << "File size: " << fs::file_size("file.txt") << "\n";
}
// 路径操作
fs::path p = "/home/user/documents/file.txt";
std::cout << "Filename: " << p.filename() << "\n";
std::cout << "Extension: " << p.extension() << "\n";
std::cout << "Parent: " << p.parent_path() << "\n";
// 相对路径
std::cout << "Relative: " << fs::relative(p) << "\n";std::scoped_lock
#include <mutex>
std::mutex mtx1, mtx2;
// C++17 之前:手动 lock
std::lock(mtx1, mtx2);
std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);
std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);
// C++17:scoped_lock 自动管理多个锁,完全替代 std::lock_guard
std::scoped_lock lock(mtx1, mtx2);
// 自动以避免死锁的方式获取所有锁
// 析构时自动释放__has_include
#if __has_include(<optional>)
#include <optional>
#endif
#if __has_include(<filesystem>) && __has_include(<version>)
#include <filesystem>
#define HAS_FILESYSTEM 1
#else
#define HAS_FILESYSTEM 0
#endif并行算法
#include <algorithm>
#include <execution>
std::vector<int> vec(1000000);
std::iota(vec.begin(), vec.end(), 0);
// 执行策略
std::sort(std::execution::par, vec.begin(), vec.end()); // 并行
std::sort(std::execution::seq, vec.begin(), vec.end()); // 顺序
std::sort(std::execution::par_unseq, vec.begin(), vec.end()); // 并行+向量化
// 并行查找
auto it = std::find(std::execution::par, vec.begin(), vec.end(), 42);
// 并行变换
std::transform(std::execution::par, vec.begin(), vec.end(), vec.begin(),
[](int x) { return x * 2; });std::shared_mutex
#include <shared_mutex>
class ThreadSafeCache {
mutable std::shared_mutex mtx_;
std::unordered_map<std::string, std::string> cache_;
public:
// 读操作:使用共享锁
std::string read(const std::string& key) const {
std::shared_lock<std::shared_mutex> lock(mtx_);
auto it = cache_.find(key);
return it != cache_.end() ? it->second : "";
}
// 写操作:使用独占锁
void write(const std::string& key, const std::string& value) {
std::unique_lock<std::shared_mutex> lock(mtx_);
cache_[key] = value;
}
};常用特性总结
最常用的 C++17 特性:
- 结构化绑定
std::optionalstd::variantstd::string_viewstd::invoke- if 初始化语句
std::filesystem[[nodiscard]]属性








