C++17标志着C++进入现代化的重要里程碑,其设计理念体现在:
- 表达力优先:让代码更接近程序员的思维模式
- 类型安全增强:通过编译期检查避免运行时错误
- 性能与安全并重:零开销抽象的同时提供类型安全
- 元编程民主化:让模板元编程更易使用
- 标准库现代化:引入函数式编程和类型安全容器
// 替代繁琐的tie和pair访问
std::pair<int, std::string> get_data() {
return {42, "hello"};
}
// C++11/14的做法
auto data = get_data();
int id = data.first;
std::string name = data.second;
// C++17结构化绑定
auto [id, name] = get_data(); // 直接解构struct Point { int x, y; };
Point p{3, 4};
auto [a, b] = p; // 编译器生成:
/*
auto __temp = p;
auto& a = __temp.x; // 引用到成员
auto& b = __temp.y;
*/
// 引用绑定
auto& [rx, ry] = p; // rx, ry是p.x, p.y的引用
// const绑定
const auto& [cx, cy] = p; // const引用// 1. 数组绑定
int arr[3] = {1, 2, 3};
auto [a, b, c] = arr;
// 2. tuple-like类型
std::tuple<int, float, std::string> t{1, 2.5f, "test"};
auto [i, f, s] = t;
// 3. 自定义类型的支持
class Custom {
public:
template<size_t I> auto get() const; // 需要实现get<>
};
// 特化std::tuple_size和std::tuple_element
template<>
struct std::tuple_size<Custom> : std::integral_constant<size_t, 2> {};
template<size_t I>
struct std::tuple_element<I, Custom> { using type = int; };// 遍历map的优雅方式
std::map<std::string, int> scores;
for (const auto& [name, score] : scores) {
std::cout << name << ": " << score << '\n';
}
// 多返回值函数
auto divide_with_remainder(int dividend, int divisor) {
return std::make_pair(dividend / divisor, dividend % divisor);
}
auto [quotient, remainder] = divide_with_remainder(17, 5);
// 与算法结合
auto [min_it, max_it] = std::minmax_element(vec.begin(), vec.end());// C++11/14需要的复杂特化
template<typename T>
std::enable_if_t<std::is_integral_v<T>, T>
process_impl(T value) {
return value * 2;
}
template<typename T>
std::enable_if_t<std::is_floating_point_v<T>, T>
process_impl(T value) {
return value * 2.5;
}
// C++17的简洁方案
template<typename T>
T process(T value) {
if constexpr (std::is_integral_v<T>) {
return value * 2;
} else if constexpr (std::is_floating_point_v<T>) {
return value * 2.5;
} else {
return value; // 其他类型
}
}// 递归打印tuple
template<typename Tuple, size_t Index = 0>
void print_tuple(const Tuple& t) {
std::cout << std::get<Index>(t);
if constexpr (Index + 1 < std::tuple_size_v<Tuple>) {
std::cout << ", ";
print_tuple<Tuple, Index + 1>(t);
}
}
// 类型列表的编译期处理
template<typename T>
constexpr size_t type_size() {
if constexpr (std::is_void_v<T>) {
return 0;
} else if constexpr (std::is_reference_v<T>) {
return sizeof(void*);
} else {
return sizeof(T);
}
}template<typename Container>
void process_container(Container& c) {
if constexpr (requires { c.size(); }) { // C++20 concepts预告
std::cout << "Size: " << c.size() << '\n';
}
if constexpr (std::is_same_v<Container, std::vector<typename Container::value_type>>) {
// 特殊处理vector
c.reserve(c.size() * 2);
}
}template<typename... Args>
auto sum(Args... args) {
return (... + args); // 左折叠: ((arg1 + arg2) + arg3) + ...
}
template<typename... Args>
auto sum_right(Args... args) {
return (args + ...); // 右折叠: arg1 + (arg2 + (arg3 + ...))
}
template<typename... Args>
auto sum_with_init(Args... args) {
return (0 + ... + args); // 初始值左折叠: ((0 + arg1) + arg2) + ...
}
template<typename... Args>
auto sum_with_init_right(Args... args) {
return (args + ... + 0); // 初始值右折叠: arg1 + (arg2 + (... + 0))
}template<typename... Conditions>
bool all_true(Conditions... conds) {
return (conds && ...); // 短路求值
}
template<typename... Conditions>
bool any_true(Conditions... conds) {
return (conds || ...);
}
// 类型检查的折叠
template<typename T, typename... Types>
constexpr bool is_any_of = (std::is_same_v<T, Types> || ...);
static_assert(is_any_of<int, float, double, int>); // truetemplate<typename... Funcs>
void call_all(Funcs... funcs) {
(funcs(), ...); // 逗号折叠,依次调用所有函数
}
template<typename... Args>
void print_all(Args... args) {
((std::cout << args << ' '), ...); // 批量输出
std::cout << '\n';
}
// 复杂的嵌套应用
template<typename... Containers>
auto concat_containers(Containers... containers) {
using ValueType = std::common_type_t<typename Containers::value_type...>;
std::vector<ValueType> result;
// 计算总大小
size_t total_size = (containers.size() + ...);
result.reserve(total_size);
// 批量插入
(result.insert(result.end(), containers.begin(), containers.end()), ...);
return result;
}// C++14及之前
std::pair<int, std::string> p1{42, "hello"};
std::vector<int> vec1{1, 2, 3, 4, 5};
// C++17类模板参数推导
std::pair p2{42, "hello"}; // 推导为std::pair<int, const char*>
std::vector vec2{1, 2, 3, 4, 5}; // 推导为std::vector<int>// 标准库提供的推导指引
template<typename T>
vector(std::initializer_list<T>) -> vector<T>;
// 自定义类的推导指引
template<typename T>
class MyContainer {
std::vector<T> data;
public:
MyContainer(std::initializer_list<T> list) : data(list) {}
template<typename Iter>
MyContainer(Iter first, Iter last) : data(first, last) {}
};
// 自定义推导指引
template<typename Iter>
MyContainer(Iter, Iter) -> MyContainer<typename std::iterator_traits<Iter>::value_type>;
// 使用
MyContainer c1{1, 2, 3}; // MyContainer<int>
MyContainer c2(vec.begin(), vec.end()); // MyContainer<int>// 函数模板的返回类型推导
template<typename T>
auto make_shared_vector(std::initializer_list<T> list) {
return std::make_shared<std::vector<T>>(list);
}
auto vec_ptr = make_shared_vector({1, 2, 3}); // shared_ptr<vector<int>>// C++14及之前的问题
// header.h
extern int global_counter; // 声明
// source.cpp
int global_counter = 0; // 定义
// C++17解决方案
// header.h
inline int global_counter = 0; // 声明即定义template<typename T>
inline constexpr bool is_integral_v = std::is_integral<T>::value;
// 替代C++14的冗长写法
template<typename T>
constexpr bool is_integral_v_old = std::is_integral<T>::value; // 每个翻译单元都有定义class Config {
public:
static inline int max_connections = 100; // 类内初始化
static inline std::string app_name = "MyApp";
// 复杂类型的内联初始化
static inline std::vector<std::string> valid_extensions{".txt", ".log", ".dat"};
};
// 无需在cpp文件中定义// C++14的问题代码
std::string* find_user(int id) {
// 返回nullptr表示未找到
if (users.count(id)) {
return &users[id];
}
return nullptr; // 潜在的空指针解引用风险
}
// C++17的解决方案
std::optional<std::string> find_user_safe(int id) {
if (users.count(id)) {
return users[id];
}
return std::nullopt; // 显式表示"无值"
}std::optional<int> parse_int(const std::string& str) {
try {
return std::stoi(str);
} catch (...) {
return std::nullopt;
}
}
// 链式处理
auto process_input(const std::string& input) {
return parse_int(input)
.and_then([](int val) -> std::optional<int> { // C++23特性预告
return val > 0 ? std::optional{val * 2} : std::nullopt;
});
}
// 实际使用
if (auto result = find_user_safe(123)) {
std::cout << "Found: " << *result << '\n';
} else {
std::cout << "User not found\n";
}// optional的内存布局优化
template<typename T>
class optional {
alignas(T) char storage[sizeof(T)]; // 原地存储,避免堆分配
bool has_value_;
public:
T& value() & {
if (!has_value_) throw std::bad_optional_access{};
return *reinterpret_cast<T*>(storage);
}
T&& value() && { // 移动版本
return std::move(value());
}
};// C风格union的问题
union UnsafeData {
int i;
float f;
char* str; // 不知道当前存储的是什么类型
};
// C++17的类型安全替代
std::variant<int, float, std::string> safe_data;
safe_data = 42; // 存储int
safe_data = 3.14f; // 现在存储float
safe_data = "hello"; // 现在存储string// 1. std::get访问(可能抛异常)
try {
int value = std::get<int>(safe_data);
} catch (const std::bad_variant_access&) {
// 类型不匹配
}
// 2. std::get_if安全访问
if (auto* ptr = std::get_if<int>(&safe_data)) {
std::cout << "Integer: " << *ptr << '\n';
}
// 3. std::visit访问器模式
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int>) {
std::cout << "Integer: " << arg << '\n';
} else if constexpr (std::is_same_v<T, float>) {
std::cout << "Float: " << arg << '\n';
} else {
std::cout << "String: " << arg << '\n';
}
}, safe_data);// 重载的访问器
struct DataProcessor {
void operator()(int i) { std::cout << "Processing integer: " << i << '\n'; }
void operator()(float f) { std::cout << "Processing float: " << f << '\n'; }
void operator()(const std::string& s) { std::cout << "Processing string: " << s << '\n'; }
};
std::visit(DataProcessor{}, safe_data);
// 通用lambda访问器
auto generic_visitor = [](auto&& value) {
std::cout << "Value: " << value << ", Type: " << typeid(value).name() << '\n';
};
std::visit(generic_visitor, safe_data);// C++14的问题:频繁的字符串拷贝
void process_string(const std::string& str) { // 可能触发拷贝
// 只是读取操作
std::cout << str.substr(0, 5) << '\n'; // 又一次拷贝
}
// C++17的解决方案
void process_string_view(std::string_view sv) { // 零拷贝
std::cout << sv.substr(0, 5) << '\n'; // 零拷贝子串
}
// 兼容各种字符串源
process_string_view("literal"); // C字符串字面值
process_string_view(std::string{"str"}); // std::string
process_string_view(char_array); // char数组std::string_view create_view() {
std::string local = "temporary";
return local; // 危险!返回了指向局部对象的视图
} // local被销毁,返回的string_view指向野指针
// 安全的做法
std::string_view safe_create_view() {
static const std::string static_str = "permanent";
return static_str; // 安全:static对象生命周期足够长
}// 零拷贝的字符串分割
std::vector<std::string_view> split(std::string_view str, char delimiter) {
std::vector<std::string_view> tokens;
size_t start = 0;
for (size_t pos = 0; pos < str.size(); ++pos) {
if (str[pos] == delimiter) {
if (pos > start) {
tokens.emplace_back(str.substr(start, pos - start));
}
start = pos + 1;
}
}
if (start < str.size()) {
tokens.emplace_back(str.substr(start));
}
return tokens;
}#include <execution>
#include <algorithm>
#include <numeric>
std::vector<int> data(1'000'000);
std::iota(data.begin(), data.end(), 1);
// 串行执行(传统)
auto sum1 = std::accumulate(data.begin(), data.end(), 0);
// 并行执行
auto sum2 = std::reduce(std::execution::par, data.begin(), data.end(), 0);
// 向量化执行(SIMD)
auto sum3 = std::reduce(std::execution::par_unseq, data.begin(), data.end(), 0);
// 串行但允许向量化
auto sum4 = std::reduce(std::execution::unseq, data.begin(), data.end(), 0);// 大数据集的并行排序
std::vector<double> large_dataset(10'000'000);
std::sort(std::execution::par, large_dataset.begin(), large_dataset.end());
// 并行变换
std::vector<int> input(1'000'000);
std::vector<double> output(1'000'000);
std::transform(std::execution::par_unseq,
input.begin(), input.end(), output.begin(),
[](int x) { return std::sqrt(x * x + 1.0); });
// 并行查找
auto it = std::find_if(std::execution::par,
data.begin(), data.end(),
[](int x) { return is_prime(x); });// C++14写法
namespace Company {
namespace Project {
namespace Module {
class Component {};
}
}
}
// C++17简化写法
namespace Company::Project::Module {
class Component {};
}// C++11/14的复杂异常规范被废弃
void func() throw(std::exception); // 废弃
// C++17只保留noexcept
void safe_func() noexcept; // 不抛出异常
void may_throw_func(); // 可能抛出异常// 返回值优化现在是强制的
std::string create_string() {
return std::string("hello"); // 强制省略拷贝构造函数
}
auto str = create_string(); // 没有拷贝发生C++17体现了现代C++的核心设计理念:
- 结构化绑定让解构变得自然
- if constexpr统一了模板分支逻辑
- 折叠表达式简化了参数包处理
- std::optional消除了空指针风险
- std::variant提供了类型安全的联合体
- std::string_view在性能和安全间找到平衡
- 并行算法利用多核性能
- 内联变量简化了全局状态管理
- CTAD减少了模板使用的繁琐
C++17标准库引入了函数式编程思想,提供了更安全、更高效的抽象,为C++20的更大变革奠定了基础。
这些特性共同构成了现代C++的基础设施,让C++在保持性能优势的同时,显著提升了开发者的编程体验。