乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • C++ 学习路径
  • 第1章 C++概述与开发环境

    • C++ 语言概述与编译模型
    • 第一个 C++ 程序与规范
    • 开发环境配置
    • 预处理指令详解
  • 第2章 基本语法与类型系统

    • 变量与基本类型
    • 类型转换
    • 枚举类型
    • 引用与指针
    • 数组与 stdarray
    • 字符串与原始字符串字面量
    • const 与 constexpr
    • nullptr 与空指针
    • 类型推导 auto 与 decltype
    • 基于范围的 for 循环
    • 值类别全面解析
    • char16_t 与 char32_t
    • static_assert 编译期断言
  • 第3章 函数与重载

    • 函数声明与定义
    • 函数重载
    • 默认参数与内联函数
    • Lambda 表达式
    • 函数对象与 stdfunction
    • 后置返回类型与 noexcept
  • 第4章 类与对象

    • 类的基本定义
    • 构造函数与析构函数
    • 拷贝控制
    • 移动构造函数与移动赋值
    • 列表初始化与类内初始化器
    • 静态成员与嵌套类
    • 友元
    • =default 与 =delete
  • 第5章 继承与多态

    • 继承基础
    • 虚函数与多态
    • 虚函数表与动态绑定原理
    • 虚析构函数
    • 抽象类与纯虚函数
    • 多重继承与虚继承
    • 继承构造函数
  • 第6章 运算符重载

    • 运算符重载基础
    • 算术与关系运算符重载
    • 赋值与移动运算符重载
    • 特殊运算符重载
  • 第7章 模板与泛型编程

    • 函数模板
    • 类模板
    • 模板特化与偏特化
    • 可变参数模板
    • 别名模板与模板模板参数
    • SFINAE 与类型萃取
    • 依赖名与 typename/template 关键字
  • 第8章 异常处理

    • 异常处理机制
    • noexcept 与异常安全
    • RAII 与异常安全实践
  • 第9章 内存管理与智能指针

    • 动态内存与内存分区
    • RAII 惯用法
    • unique_ptr
    • shared_ptr 与 weak_ptr
    • 内存管理最佳实践
  • 第10章 右值引用与移动语义

    • 右值引用与值类别深度解析
    • std::move 原理与使用
    • 完美转发与 std::forward
    • 移动语义性能对比与最佳实践
  • 第11章 STL容器

    • vector 深度剖析
    • deque 内部机制
    • list 与 forward_list
    • map 与 set 深度解析
    • unordered 容器与哈希原理
    • array 与 tuple
    • 容器适配器
    • 容器选择全景指南
  • 第12章 STL算法与迭代器

    • 迭代器体系全解
    • 非变异算法
    • 变异算法
    • 排序与二分算法
    • Lambda 与算法组合
    • std::random 随机数库
    • 自定义迭代器开发
  • 第13章 IO流与文件

    • 标准 IO 流
    • 格式化输出控制
    • 文件流操作
    • 字符串流
    • std::regex 正则表达式
  • 第14章 并发与多线程

    • thread 基础与线程管理
    • mutex 与 lock_guard
    • unique_lock 与 condition_variable
    • thread_local 线程局部存储
    • atomic 与内存序
    • future 与 async 异步编程
    • std::chrono 时间库
  • 第15章 现代C++新特性

    • 从 C++11 到 C++20 演进路线
    • C++14 关键新特性
    • C++17 关键新特性
    • C++20 核心特性速览
  • 第16章 面试考点与最佳实践

    • C++ 综合最佳实践清单
    • 高频面试题精讲
    • 多线程面试题与实战
    • 内存管理常见陷阱与排查
  • 附录

    • C++ 核心知识点
    • C++ 专业术语

C++17 关键新特性

定义与作用

C++17 是一次重要的标准更新,引入了结构化绑定、if constexpr、std::optional/variant/any、折叠表达式和 string_view 等关键特性,显著提升了代码的表达力和安全性。

核心原理

C++17 特性全景

完整示例

示例一:结构化绑定与 optional 重构用户服务

场景说明:黄俪用结构化绑定和 optional 重构飞翔科技用户查询。

#include <iostream>
#include <optional>
#include <string>
#include <map>
#include <vector>

struct User {
    int id;
    std::string name;
    std::string email;
    std::string role;
};

class UserService {
public:
    void addUser(User u) {
        users_[u.id] = std::move(u);
    }

    // C++17: optional 表示可能无值
    std::optional<User> findById(int id) const {
        auto it = users_.find(id);
        if (it != users_.end())
            return it->second;
        return std::nullopt;
    }

    // 返回结构化绑定所需数据
    std::vector<User> allUsers() const {
        std::vector<User> result;
        for (const auto& [id, user] : users_)  // 结构化绑定
            result.push_back(user);
        return result;
    }

private:
    std::map<int, User> users_;
};

int main() {
    std::cout << "=== 飞翔科技用户查询系统 (C++17) ===\n\n";

    UserService svc;
    svc.addUser({1, "大翔",  "daxiang@feixiang.net",   "CTO"});
    svc.addUser({2, "白歌",  "baige@feixiang.net",     "架构师"});
    svc.addUser({3, "孔蓝",  "konglan@feixiang.net",   "产品经理"});
    svc.addUser({4, "黄俪",  "huangli@feixiang.net",   "前端开发"});

    // 1. optional 处理查询
    std::cout << "--- 可选值查询 ---\n";
    auto user = svc.findById(2);
    if (user) {
        // 结构化绑定
        auto [id, name, email, role] = *user;
        std::cout << "ID:" << id << " 姓名:" << name
                  << " 邮箱:" << email << " 角色:" << role << "\n";
    }

    auto missing = svc.findById(99);
    std::cout << "用户 99 存在: " << (missing.has_value() ? "是" : "否") << "\n\n";

    // 2. 结构化绑定遍历
    std::cout << "--- 全量用户遍历 ---\n";
    for (const auto& user : svc.allUsers()) {
        auto [id, name, email, role] = user;
        std::cout << "  [" << id << "] " << name << " <" << email << ">\n";
    }

    // 3. if constexpr 编译期分支
    std::cout << "\n--- 编译期分支 ---\n";
    auto printTypeInfo = [](const auto& val) {
        if constexpr (std::is_integral_v<decltype(val)>) {
            std::cout << "整型值: " << val << " (sizeof="
                      << sizeof(val) << ")\n";
        } else if constexpr (std::is_floating_point_v<decltype(val)>) {
            std::cout << "浮点值: " << val << " (sizeof="
                      << sizeof(val) << ")\n";
        } else {
            std::cout << "其他类型: sizeof=" << sizeof(val) << "\n";
        }
    };

    printTypeInfo(42);
    printTypeInfo(3.14);
    printTypeInfo(std::string("hello"));
}

预期输出:

=== 飞翔科技用户查询系统 (C++17) ===

--- 可选值查询 ---
ID:2 姓名:白歌 邮箱:baige@feixiang.net 角色:架构师
用户 99 存在: 否

--- 全量用户遍历 ---
  [1] 大翔 <daxiang@feixiang.net>
  [2] 白歌 <baige@feixiang.net>
  [3] 孔蓝 <konglan@feixiang.net>
  [4] 黄俪 <huangli@feixiang.net>

--- 编译期分支 ---
整型值: 42 (sizeof=4)
浮点值: 3.14 (sizeof=8)
其他类型: sizeof=32

逐段分析:

  • 结构化绑定 auto [a, b] = pair 解包 tuple-like 类型
  • optional<T> 明确表达"可能无值",替代返回指针或特殊值
  • if constexpr 在编译期评估条件,不匹配分支不被实例化
  • has_value() 检测 optional 是否有值

示例二:variant、any 与 string_view

场景说明:大翔用 variant 和 any 实现灵活的配置系统。

#include <iostream>
#include <variant>
#include <any>
#include <string_view>
#include <string>
#include <vector>
#include <unordered_map>

// C++17 variant:类型安全的 union
using ConfigValue = std::variant<int, double, std::string, bool>;

class ConfigCenter {
public:
    void set(std::string_view key, ConfigValue val) {
        configs_[std::string(key)] = std::move(val);
    }

    // 使用 std::visit 多态访问 variant
    void printAll() const {
        for (const auto& [key, val] : configs_) {
            std::cout << "  " << key << " = ";
            std::visit([](const auto& v) {
                using T = std::decay_t<decltype(v)>;
                if constexpr (std::is_same_v<T, std::string>)
                    std::cout << "\"" << v << "\"";
                else if constexpr (std::is_same_v<T, bool>)
                    std::cout << (v ? "true" : "false");
                else
                    std::cout << v;
            }, val);
            std::cout << "\n";
        }
    }

private:
    std::unordered_map<std::string, ConfigValue> configs_;
};

// C++17 string_view:零拷贝字符串引用
void analyzeLog(std::string_view log) {
    // 不需要分配内存,直接引用原字符串
    if (log.find("ERROR") != std::string_view::npos) {
        std::cout << "  [告警] 错误日志: " << log.substr(0, 40) << "...\n";
    }
}

int main() {
    std::cout << "=== 飞翔科技配置中心 (C++17) ===\n\n";

    // 1. variant 配置
    ConfigCenter cc;
    cc.set("server.port",      443);
    cc.set("server.host",      std::string("0.0.0.0"));
    cc.set("cache.ttl",        3600.0);
    cc.set("debug.enabled",    false);
    cc.set("max.connections",  10000);

    std::cout << "--- 配置项 ---\n";
    cc.printAll();

    // 2. any:类型擦除
    std::cout << "\n--- std::any 运行时多态 ---\n";
    std::vector<std::any> genericList;
    genericList.push_back(42);
    genericList.push_back(std::string("飞翔科技"));
    genericList.push_back(3.14159);
    genericList.push_back(true);

    for (const auto& item : genericList) {
        if (item.type() == typeid(int))
            std::cout << "  int: " << std::any_cast<int>(item) << "\n";
        else if (item.type() == typeid(std::string))
            std::cout << "  string: " << std::any_cast<std::string>(item) << "\n";
        else if (item.type() == typeid(double))
            std::cout << "  double: " << std::any_cast<double>(item) << "\n";
        else if (item.type() == typeid(bool))
            std::cout << "  bool: " << std::any_cast<bool>(item) << "\n";
    }

    // 3. string_view 零拷贝
    std::cout << "\n--- string_view 日志分析 ---\n";
    std::string rawLog =
        "INFO: 服务启动\n"
        "ERROR: 数据库连接超时,请检查网络配置\n"
        "INFO: 健康检查通过\n"
        "WARN: 内存使用率达到 85%\n";

    // 不复制,直接分析
    analyzeLog(rawLog);

    // 对子串创建 string_view 也不分配内存
    std::string_view sv(rawLog);
    auto pos = sv.find("健康检查");
    if (pos != std::string_view::npos) {
        std::string_view sub = sv.substr(pos, 12);
        std::cout << "  子串(零拷贝): " << sub << "\n";
    }

    // 4. 折叠表达式
    std::cout << "\n--- 折叠表达式 ---\n";
    auto sumAll = [](auto... args) {
        return (... + args);  // 一元右折叠
    };
    std::cout << "sumAll(1,2,3,4,5) = " << sumAll(1, 2, 3, 4, 5) << "\n";

    auto printAll = [](auto... args) {
        ((std::cout << args << " "), ...);  // 逗号折叠
    };
    std::cout << "printAll: ";
    printAll("飞翔", "科技", 2025);
    std::cout << "\n";
}

预期输出:

=== 飞翔科技配置中心 (C++17) ===

--- 配置项 ---
  server.port = 443
  server.host = "0.0.0.0"
  cache.ttl = 3600
  debug.enabled = false
  max.connections = 10000

--- std::any 运行时多态 ---
  int: 42
  string: 飞翔科技
  double: 3.14159
  bool: 1

--- string_view 日志分析 ---
  [告警] 错误日志: ERROR: 数据库连接超时,请检查网络配置...
  子串(零拷贝): 健康检查通过

--- 折叠表达式 ---
sumAll(1,2,3,4,5) = 15
printAll: 飞翔 科技 2025

逐段分析:

  • variant 是类型安全的 union,std::visit 实现多态访问
  • any 可以存储任意可拷贝类型,通过 any_cast 提取
  • string_view 不拥有字符串,只是引用,适用于只读场景
  • 折叠表达式 (... + args) 替代递归模板展开可变参数
  • if constexpr 配合 std::visit 实现编译期类型分派

易错场景与面试考点

易错场景

1. string_view 悬挂引用

std::string_view getView() {
    std::string s = "临时";
    return std::string_view(s);  // ❌ s 被销毁,view 悬挂
}

2. any_cast 类型不匹配

std::any a = 42;
auto s = std::any_cast<std::string>(a);  // ❌ 抛 std::bad_any_cast

3. variant 类型检查

std::variant<int, std::string> v = 42;
// 用 std::get 需知道准确类型,否则抛异常
// 用 std::visit 或 std::holds_alternative 安全

面试考点

特性要点
结构化绑定auto [a, b] = pair/map::value_type/struct
if constexpr编译期分支,丢弃分支不被实例化
折叠表达式(... op args) 左折叠, (args op ...) 右折叠
optionalhas_value() / value() / value_or(default)
variantstd::visit / std::get<T> / std::holds_alternative<T>
anyany_cast<T> / type() / has_value()
string_view零拷贝、不拥有数据,注意生命周期
CTAD类模板参数推导:vector v{1,2,3}
std::filesystemC++17 文件系统库
上一页
C++14 关键新特性
下一页
C++20 核心特性速览