C++11的新特性
这里就不详细罗列了,只是说特性有哪些
1️⃣ auto(类型推导)
2️⃣ nullptr(干掉 NULL)
3️⃣ 智能指针(核心中的核心)
4️⃣ lambda 表达式
5️⃣ range-for (for-each)
6️⃣ move 语义 & 右值引用(性能关键)
C++14 (C++11补丁版)
1️⃣ auto 返回值
auto add(int a, int b) {
return a + b;
}
📌 工程价值
- 泛型函数更自然
2️⃣ lambda 支持 auto 参数
auto lambda = [](auto a, auto b) {
return a + b;
};
lambda(1, 2);
lambda(1.5, 2.3);
📌 工程价值
- 泛型算法写起来像脚本
C++17新特性
结构化绑定
定义
structured bindings(结构化绑定)
std::map<int, std::string> m;
for (auto& [key, value] : m) {
std::cout << key << value;
}
📌 工程价值
- 遍历 map 不再
first / second - 代码可读性爆炸提升
用例
从元组/结构体解包 到 变量上面
auto [x, y] = std::pair{1, 2.0};
c
#include <iostream>
#include <tuple>
#include <map>
#include <string>
// 定义:从元组、数组或结构体中将多个变量绑定到成员
// 示例1:从pair解包 到对应的变量上面
void example_pair() {
std::pair<int, double> p{42, 3.14};
auto [x, y] = p; // x=42, y=3.14
std::cout << "x=" << x << ", y=" << y << std::endl;
}
// 示例2:从tuple解包 到对应的变量上面
void example_tuple() {
auto t = std::make_tuple(1, "hello", 4.5);
auto [a, b, c] = t; // a=1, b="hello", c=4.5
std::cout << "a=" << a << ", b=" << b << ", c=" << c << std::endl;
}
// 示例3:从数组解包 到对应的变量上面
void example_array() {
int arr[3] = {10, 20, 30};
auto [first, second, third] = arr; // 数组大小必须匹配
std::cout << first << " " << second << " " << third << std::endl;
}
// 示例4:从结构体解包 到对应的变量上面
struct Point {
int x;
int y;
std::string name;
};
void example_struct() {
Point p{100, 200, "origin"};
auto [x_coord, y_coord, point_name] = p;
std::cout << point_name << ": (" << x_coord << ", " << y_coord << ")\n";
}
// 示例5:在循环中使用 到对应的变量上面
void example_loop() {
std::map<int, std::string> m = {
{1, "one"},
{2, "two"},
{3, "three"}
};
// 传统方式
for (const auto& kv : m) {
std::cout << kv.first << ": " << kv.second << std::endl;
}
// 使用结构化绑定
for (const auto& [key, value] : m) {
std::cout << key << ": " << value << std::endl;
}
}
// 示例6:使用引用
void example_reference() {
std::pair<int, std::string> p{1, "test"};
auto& [num, str] = p; // 使用引用,修改会影响原值
num = 100;
std::cout << p.first << std::endl; // 输出100
}
int main() {
example_pair();
example_tuple();
example_array();
example_struct();
example_loop();
example_reference();
return 0;
}
if/switch 初始化语句
定义
if / switch 初始化语句 ⭐⭐⭐⭐⭐
if (auto it = map.find(key); it != map.end()) {
std::cout << it->second;
}
📌 工程价值
- 变量作用域最小化
- 写 UI / 状态判断特别干净
用例
c
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <mutex>
#include <memory>
// 定义:在if/switch条件中初始化变量,变量作用域限于条件语句块
// 示例1:基本用法
void example_basic() {
std::map<int, std::string> m = {{1, "one"}, {2, "two"}};
// 传统方式
{
auto it = m.find(1);
if (it != m.end()) {
std::cout << "Found: " << it->second << std::endl;
}
}
// C++17方式:更简洁,it作用域限于if语句
if (auto it = m.find(1); it != m.end()) {
std::cout << "Found: " << it->second << std::endl;
}
// it在这里不可访问
// 可以使用else if
if (auto it = m.find(3); it != m.end()) {
std::cout << "Found: " << it->second << std::endl;
} else {
std::cout << "Not found" << std::endl;
}
}
// 示例2:锁的获取和检查
void example_lock() {
std::mutex mtx;
std::vector<int> shared_data;
// 传统方式
{
std::lock_guard<std::mutex> lock(mtx);
if (!shared_data.empty()) {
std::cout << "Data size: " << shared_data.size() << std::endl;
}
}
// C++17方式:锁的作用域明确
if (std::lock_guard<std::mutex> lock(mtx); !shared_data.empty()) {
std::cout << "Data size: " << shared_data.size() << std::endl;
}
}
// 示例3:资源管理
void example_resource() {
// 传统方式:需要额外的{}限制作用域
{
std::unique_ptr<int> ptr = std::make_unique<int>(42);
if (ptr) {
std::cout << *ptr << std::endl;
}
}
// C++17方式
if (auto ptr = std::make_unique<int>(42); ptr) {
std::cout << *ptr << std::endl;
}
// ptr已自动释放
}
// 示例4:switch中的初始化
void example_switch(int value) {
// 传统方式
{
auto result = value * 2;
switch (result) {
case 2: std::cout << "Two"; break;
default: std::cout << "Other"; break;
}
}
// C++17方式
switch (auto result = value * 2; result) {
case 2:
std::cout << "Two";
break;
case 4:
std::cout << "Four";
break;
default:
std::cout << "Other: " << result;
break;
}
}
// 示例5:类型检查和转换
void example_type_check() {
class Base { public: virtual ~Base() = default; };
class Derived : public Base { public: void specific() {} };
Base* base_ptr = new Derived();
// 传统方式
{
Derived* derived = dynamic_cast<Derived*>(base_ptr);
if (derived) {
derived->specific();
}
}
// C++17方式
if (Derived* derived = dynamic_cast<Derived*>(base_ptr); derived) {
derived->specific();
}
delete base_ptr;
}
// 示例6:错误处理
#include <system_error>
#include <fstream>
void example_error_handling() {
// 文件操作中的错误检查
if (std::ifstream file{"data.txt"}; file.is_open()) {
std::string content;
std::getline(file, content);
std::cout << "Content: " << content << std::endl;
} else {
std::cout << "Failed to open file" << std::endl;
}
}
// 示例7:多重条件
void example_multi_condition() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 传统方式
{
auto it = std::find(vec.begin(), vec.end(), 3);
if (it != vec.end() && *it > 2) {
std::cout << "Found and value > 2" << std::endl;
}
}
// C++17方式
if (auto it = std::find(vec.begin(), vec.end(), 3);
it != vec.end() && *it > 2) {
std::cout << "Found and value > 2" << std::endl;
}
}
int main() {
example_basic();
example_lock();
example_resource();
example_switch(2);
example_type_check();
example_error_handling();
example_multi_condition();
return 0;
}
constexpr if - 编译期条件判断
c
#include <iostream>
#include <type_traits>
#include <vector>
#include <string>
// 定义:在编译期进行条件判断,未选中的分支不会实例化
// 示例1:基本用法
template<typename T>
auto get_value(T t) {
// 编译期判断T是否为指针类型
if constexpr (std::is_pointer_v<T>) {
std::cout << "Pointer: ";
return *t; // 解引用
} else {
std::cout << "Value: ";
return t; // 直接返回
}
}
void example_basic() {
int x = 42;
int* ptr = &x;
std::cout << get_value(x) << std::endl; // 输出: Value: 42
std::cout << get_value(ptr) << std::endl; // 输出: Pointer: 42
}
// 示例2:处理不同类型
template<typename T>
void process(T value) {
if constexpr (std::is_integral_v<T>) {
std::cout << "Integral: " << value * 2 << std::endl;
} else if constexpr (std::is_floating_point_v<T>) {
std::cout << "Floating: " << value * 1.5 << std::endl;
} else if constexpr (std::is_pointer_v<T>) {
std::cout << "Pointer to: " << *value << std::endl;
} else {
std::cout << "Other type" << std::endl;
}
}
// 示例3:元编程 - 编译期计算
template<int N>
constexpr int factorial() {
if constexpr (N <= 1) {
return 1;
} else {
return N * factorial<N - 1>();
}
}
// 示例4:处理不同容器的迭代
template<typename Container>
void print_container(const Container& container) {
if constexpr (std::is_same_v<Container, std::string>) {
// 字符串特殊处理
std::cout << "String: " << container << std::endl;
} else {
// 其他容器通用处理
std::cout << "Container elements: ";
for (const auto& elem : container) {
std::cout << elem << " ";
}
std::cout << std::endl;
}
}
// 示例5:SFINAE的现代替代
template<typename T, typename = void>
struct has_size_method : std::false_type {};
template<typename T>
struct has_size_method<T, std::void_t<decltype(std::declval<T>().size())>>
: std::true_type {};
template<typename T>
void check_size(const T& obj) {
if constexpr (has_size_method<T>::value) {
std::cout << "Has size: " << obj.size() << std::endl;
} else {
std::cout << "No size method" << std::endl;
}
}
// 示例6:类型特化
template<typename T>
class MyClass {
public:
void process() {
if constexpr (std::is_same_v<T, int>) {
std::cout << "Processing int type" << std::endl;
// 只能用于int的代码
} else if constexpr (std::is_same_v<T, double>) {
std::cout << "Processing double type" << std::endl;
// 只能用于double的代码
} else {
std::cout << "Processing generic type" << std::endl;
}
}
};
// 示例7:编译期字符串处理
template<typename T>
constexpr auto type_name() {
if constexpr (std::is_same_v<T, int>) {
return "int";
} else if constexpr (std::is_same_v<T, double>) {
return "double";
} else if constexpr (std::is_same_v<T, std::string>) {
return "std::string";
} else {
return "unknown";
}
}
// 示例8:错误处理
template<typename T>
T parse_string(const std::string& str) {
if constexpr (std::is_same_v<T, int>) {
return std::stoi(str);
} else if constexpr (std::is_same_v<T, double>) {
return std::stod(str);
} else if constexpr (std::is_same_v<T, float>) {
return std::stof(str);
} else {
static_assert(false, "Unsupported type for parsing");
}
}
// 示例9:递归模板终止条件
template<int N>
struct Fibonacci {
static constexpr int value = []() {
if constexpr (N <= 1) {
return N;
} else {
return Fibonacci<N - 1>::value + Fibonacci<N - 2>::value;
}
}();
};
// 示例10:编译期与运行时结合
template<typename Func>
auto measure_time(Func&& func) {
if constexpr (std::is_same_v<decltype(func()), void>) {
// 返回void的函数
auto start = std::chrono::high_resolution_clock::now();
func();
auto end = std::chrono::high_resolution_clock::now();
return end - start;
} else {
// 有返回值的函数
auto start = std::chrono::high_resolution_clock::now();
auto result = func();
auto end = std::chrono::high_resolution_clock::now();
return std::make_pair(result, end - start);
}
}
int main() {
example_basic();
process(10); // Integral
process(3.14); // Floating
int y = 5;
process(&y); // Pointer
std::cout << "Factorial of 5: " << factorial<5>() << std::endl;
std::string str = "hello";
std::vector<int> vec = {1, 2, 3};
print_container(str); // String处理
print_container(vec); // 容器处理
check_size(str); // Has size
check_size(10); // No size method
MyClass<int> int_obj;
MyClass<double> double_obj;
MyClass<std::string> str_obj;
int_obj.process();
double_obj.process();
str_obj.process();
std::cout << "Type: " << type_name<int>() << std::endl;
std::cout << "Type: " << type_name<std::string>() << std::endl;
std::cout << "Fibonacci(10): " << Fibonacci<10>::value << std::endl;
return 0;
}
std::optional 详细用法
c
#include <iostream>
#include <optional>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
// 定义:表示一个可能存在也可能不存在的值,替代使用特殊值表示"无值"
// 示例1:基本创建和访问
void example_basic() {
// 创建有值的optional
std::optional<int> opt1 = 42;
std::optional<std::string> opt2 = "hello";
std::optional<double> opt3 = 3.14;
// 创建空optional
std::optional<int> empty_opt;
std::optional<int> empty_opt2 = std::nullopt;
// 检查是否有值
if (opt1.has_value()) {
std::cout << "opt1 has value: " << opt1.value() << std::endl;
}
// 使用bool转换检查
if (opt2) {
std::cout << "opt2 has value: " << *opt2 << std::endl;
}
// 安全访问(推荐)
if (opt3) {
std::cout << "opt3 value: " << opt3.value() << std::endl;
}
// 不安全访问(可能抛出异常)
try {
std::cout << "Empty opt: " << empty_opt.value() << std::endl;
} catch (const std::bad_optional_access& e) {
std::cout << "Exception: " << e.what() << std::endl;
}
}
// 示例2:作为函数返回值
std::optional<int> find_value(const std::vector<int>& vec, int target) {
auto it = std::find(vec.begin(), vec.end(), target);
if (it != vec.end()) {
return *it; // 找到,返回值
}
return std::nullopt; // 没找到,返回空
}
std::optional<std::string> parse_number(int num) {
if (num >= 0 && num <= 9) {
return std::to_string(num);
}
return std::nullopt;
}
void example_function_return() {
std::vector<int> numbers = {1, 3, 5, 7, 9};
// 使用返回值
auto result = find_value(numbers, 5);
if (result) {
std::cout << "Found: " << *result << std::endl;
}
// 使用value_or提供默认值
auto not_found = find_value(numbers, 2);
std::cout << "Value or default: "
<< not_found.value_or(-1) << std::endl; // 输出-1
}
// 示例3:处理复杂类型
class User {
public:
std::string name;
int age;
User(std::string n, int a) : name(std::move(n)), age(a) {}
void print() const {
std::cout << "User: " << name << ", Age: " << age << std::endl;
}
};
std::optional<User> find_user(const std::string& name) {
if (name == "Alice") {
return User{"Alice", 30};
} else if (name == "Bob") {
return User{"Bob", 25};
}
return std::nullopt;
}
// 示例4:optional的链式操作
struct Connection {
std::optional<std::string> send_request() {
return "response";
}
};
std::optional<Connection> connect() {
return Connection{};
}
std::optional<std::string> parse_response(const std::string& resp) {
if (!resp.empty()) {
return "parsed: " + resp;
}
return std::nullopt;
}
void example_chaining() {
// 传统方式
{
auto conn_opt = connect();
if (conn_opt) {
auto resp_opt = conn_opt->send_request();
if (resp_opt) {
auto parsed_opt = parse_response(*resp_opt);
if (parsed_opt) {
std::cout << *parsed_opt << std::endl;
}
}
}
}
// 使用and_then实现链式调用
auto result = connect()
.and_then([](Connection& conn) { return conn.send_request(); })
.and_then(parse_response);
if (result) {
std::cout << "Chained result: " << *result << std::endl;
}
}
// 示例5:与标准算法结合
void example_with_algorithms() {
std::vector<std::optional<int>> opts = {
1, std::nullopt, 3, std::nullopt, 5
};
// 过滤掉空值
std::vector<int> values;
for (const auto& opt : opts) {
if (opt) {
values.push_back(*opt);
}
}
// 使用transform
std::vector<std::optional<int>> transformed;
std::transform(opts.begin(), opts.end(),
std::back_inserter(transformed),
[](const auto& opt) -> std::optional<int> {
if (opt) {
return *opt * 2;
}
return std::nullopt;
});
}
// 示例6:性能优化 - 延迟初始化
class ExpensiveResource {
std::optional<std::vector<int>> cache;
public:
const std::vector<int>& get_data() {
if (!cache) {
// 延迟初始化
cache = std::vector<int>{1, 2, 3, 4, 5};
std::cout << "Initialized cache" << std::endl;
}
return *cache;
}
void clear_cache() {
cache.reset();
}
};
// 示例7:错误处理的替代方案
enum class ErrorCode {
OK,
NOT_FOUND,
INVALID_INPUT,
TIMEOUT
};
std::optional<std::string> fetch_data(ErrorCode& error) {
// 传统方式:通过输出参数返回错误
error = ErrorCode::OK;
return "data";
}
std::optional<std::string> fetch_data_modern() {
// 使用optional:要么返回数据,要么返回空
return "data";
// 或者 return std::nullopt; 表示错误
}
// 示例8:与variant结合
#include <variant>
using Result = std::variant<std::string, std::nullopt_t>;
Result process_data() {
bool success = true; // 模拟操作结果
if (success) {
return "success data";
}
return std::nullopt;
}
// 示例9:optional的引用
void process_if_present(const std::optional<std::string>& opt) {
// optional可以包含引用语义
if (opt) {
std::cout << "Processing: " << *opt << std::endl;
}
}
// 示例10:自定义类型的optional
class Config {
std::optional<std::string> theme;
std::optional<int> timeout;
std::optional<bool> debug_mode;
public:
void set_theme(const std::string& t) { theme = t; }
void set_timeout(int t) { timeout = t; }
std::string get_theme() const { return theme.value_or("default"); }
int get_timeout() const { return timeout.value_or(30); }
void print() const {
std::cout << "Theme: " << get_theme()
<< ", Timeout: " << get_timeout() << std::endl;
}
};
int main() {
example_basic();
example_function_return();
// 用户查找示例
auto user = find_user("Alice");
if (user) {
user->print();
}
// 延迟初始化示例
ExpensiveResource resource;
auto& data = resource.get_data(); // 第一次调用会初始化
auto& data2 = resource.get_data(); // 使用缓存
// 配置示例
Config config;
config.print(); // 使用默认值
config.set_theme("dark");
config.set_timeout(60);
config.print(); // 使用设置的值
return 0;
}
std::variant 详细用法
定义
std::variant(类型安全 union)
std::variant<int, double, std::string> v;
v = 10;
v = "hello";
std::visit([](auto&& arg) {
std::cout << arg;
}, v);
📌 工程价值
- 状态机
- 不同类型结果统一返回
std::visit
c++
std::variant<int, double, std::string> v = "world";
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int>) {
std::cout << "int: " << arg * 2 << std::endl;
}
else if constexpr (std::is_same_v<T, double>) {
std::cout << "double: " << arg + 0.5 << std::endl;
}
else if constexpr (std::is_same_v<T, std::string>) {
std::cout << "string length: " << arg.size() << std::endl;
}
}, v);
variant当前持有哪种类型visit自动调用 lambdaarg的真实类型在 编译期确定
📌 零运行时 RTTI / 零 dynamic_cast
多个variant一起使用的话
c
std::variant<int, double> a = 3;
std::variant<int, double> b = 4.5;
std::visit([](auto x, auto y) {
std::cout << x + y << std::endl;
}, a, b);
// 编译期展开
std::decay_t<> 作用
在上面的例子当中:
cusing T = std::decay_t<decltype(arg)>; if constexpr (std::is_same_v<T, int>) { std::cout << "int: " << arg * 2 << std::endl; }
先从 decltype(arg) 说起
1️⃣
decltype(arg)是什么?
auto&& arg = ...;
decltype(arg)
decltype(arg) 不是你以为的类型。
假设:
int x = 10;
auto&& arg = x;
那么:
decltype(arg) // 是:int&
如果:
const int y = 20;
auto&& arg = y;
那么:
decltype(arg) // 是:const int&
📌 结论 :decltype(arg) 会保留:1、引用(& / &&); 2、const / volatile
二、那
std::decay_t是干嘛的? 2️⃣std::decay<T>做了什么?
std::decay<T> ≈ "函数参数退化规则"
它会帮你:
| 原类型 | decay 后 |
|---|---|
int& |
int |
const int& |
int |
int&& |
int |
const int |
int |
T[N] |
T* |
T() |
T(*)() |
📌 核心作用
👉 去引用 + 去 const
三、合起来看:
std::decay_t<decltype(arg)>
拆解顺序
decltype(arg) // 带引用、带 const
std::decay_t<...> // 去掉引用和 const
实际例子(非常关键)
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
// T 是一个"干净类型"
}, v);
如果 variant 当前是:
| variant 内类型 | arg 实际类型 | T 最终类型 |
|---|---|---|
int |
int& |
int |
double |
double& |
double |
std::string |
std::string& |
std::string |
四、为什么不能直接用
decltype(arg)?
❌ 错误写法
if constexpr (std::is_same_v<decltype(arg), int>) {
...
}
❌ 几乎永远不成立
因为 decltype(arg) 是:
int&const int&
而你拿它去和 int 比,当然不相等。
五、正确写法对比(必背)
✅ 写法 1(最常见)
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int>) {
...
}
具体用例
c
#include <iostream>
#include <variant>
#include <string>
#include <vector>
#include <type_traits>
#include <cassert>
// 定义:类型安全的联合体,可以持有多种类型中的一种
// 示例1:基本创建和访问
void example_basic() {
// 创建variant,可以持有int, double或string
std::variant<int, double, std::string> v;
// 赋值不同类型
v = 42;
std::cout << "Holds int: " << std::get<int>(v) << std::endl;
v = 3.14;
std::cout << "Holds double: " << std::get<double>(v) << std::endl;
v = "hello";
std::cout << "Holds string: " << std::get<std::string>(v) << std::endl;
// 检查当前持有的类型索引
std::cout << "Current index: " << v.index() << std::endl; // 输出2
// 使用holds_alternative检查类型
if (std::holds_alternative<std::string>(v)) {
std::cout << "Currently holds a string" << std::endl;
}
// 安全访问(推荐)
try {
std::cout << std::get<double>(v) << std::endl; // 抛出异常
} catch (const std::bad_variant_access& e) {
std::cout << "Bad access: " << e.what() << std::endl;
}
}
// 示例2:visitor模式(使用std::visit)
// 定义visitor(函数对象)
struct PrintVisitor {
void operator()(int i) const {
std::cout << "int: " << i << std::endl;
}
void operator()(double d) const {
std::cout << "double: " << d << std::endl;
}
void operator()(const std::string& s) const {
std::cout << "string: " << s << std::endl;
}
};
// 使用lambda作为visitor
void example_visitor() {
std::variant<int, double, std::string> v = "test";
// 使用函数对象
std::visit(PrintVisitor{}, v);
// 使用lambda(C++17支持)
auto lambda_visitor = [](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int>) {
std::cout << "Got int: " << arg << std::endl;
} else if constexpr (std::is_same_v<T, double>) {
std::cout << "Got double: " << arg << std::endl;
} else if constexpr (std::is_same_v<T, std::string>) {
std::cout << "Got string: " << arg << std::endl;
}
};
v = 10;
std::visit(lambda_visitor, v);
v = 2.5;
std::visit(lambda_visitor, v);
}
// 示例3:错误处理
std::variant<std::string, std::runtime_error> parse_input(const std::string& input) {
if (input.empty()) {
return std::runtime_error("Empty input");
}
if (input[0] == 'E') {
return std::runtime_error("Input starts with E");
}
return "Processed: " + input;
}
void example_error_handling() {
auto result = parse_input("");
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, std::string>) {
std::cout << "Success: " << arg << std::endl;
} else if constexpr (std::is_same_v<T, std::runtime_error>) {
std::cout << "Error: " << arg.what() << std::endl;
}
}, result);
}
// 示例4:递归variant(树结构)
struct TreeNode;
using TreeNodeVariant = std::variant<int, std::unique_ptr<TreeNode>>;
struct TreeNode {
TreeNodeVariant left;
TreeNodeVariant right;
int value;
TreeNode(int val, TreeNodeVariant l, TreeNodeVariant r)
: value(val), left(std::move(l)), right(std::move(r)) {}
};
int calculate_tree(const TreeNodeVariant& node) {
return std::visit([](auto&& arg) -> int {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int>) {
return arg; // 叶子节点
} else {
// 内部节点
auto& tree = *arg;
int left_val = calculate_tree(tree.left);
int right_val = calculate_tree(tree.right);
return tree.value + left_val + right_val;
}
}, node);
}
// 示例5:状态机
class Connection {
public:
enum State { Disconnected, Connecting, Connected, Error };
private:
std::variant<
struct DisconnectedState,
struct ConnectingState,
struct ConnectedState,
struct ErrorState
> state;
public:
Connection() : state(DisconnectedState{}) {}
void connect() {
state = std::visit([](auto&& s) -> decltype(state) {
using T = std::decay_t<decltype(s)>;
if constexpr (std::is_same_v<T, DisconnectedState>) {
std::cout << "Starting connection..." << std::endl;
return ConnectingState{};
} else if constexpr (std::is_same_v<T, ConnectingState>) {
std::cout << "Already connecting..." << std::endl;
return s;
} else if constexpr (std::is_same_v<T, ConnectedState>) {
std::cout << "Already connected" << std::endl;
return s;
} else {
std::cout << "Cannot connect from error state" << std::endl;
return s;
}
}, state);
}
void print_state() const {
std::cout << "Current state index: " << state.index() << std::endl;
}
};
// 示例6:解析多种类型数据
struct JSONNull {};
using JSONValue = std::variant<
JSONNull,
bool,
int,
double,
std::string,
std::vector<JSONValue>,
std::map<std::string, JSONValue>
>;
void print_json(const JSONValue& value, int indent = 0) {
std::string spaces(indent * 2, ' ');
std::visit([&](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, JSONNull>) {
std::cout << spaces << "null";
} else if constexpr (std::is_same_v<T, bool>) {
std::cout << spaces << (arg ? "true" : "false");
} else if constexpr (std::is_same_v<T, int>) {
std::cout << spaces << arg;
} else if constexpr (std::is_same_v<T, double>) {
std::cout << spaces << arg;
} else if constexpr (std::is_same_v<T, std::string>) {
std::cout << spaces << "\"" << arg << "\"";
} else if constexpr (std::is_same_v<T, std::vector<JSONValue>>) {
std::cout << spaces << "[\n";
for (const auto& elem : arg) {
print_json(elem, indent + 1);
std::cout << ",\n";
}
std::cout << spaces << "]";
} else if constexpr (std::is_same_v<T, std::map<std::string, JSONValue>>) {
std::cout << spaces << "{\n";
for (const auto& [key, val] : arg) {
std::cout << spaces << " \"" << key << "\": ";
print_json(val, 0);
std::cout << ",\n";
}
std::cout << spaces << "}";
}
}, value);
}
// 示例7:类型安全的回调
using Callback = std::variant<
std::function<void(int)>,
std::function<void(std::string)>,
std::function<void(double)>
>;
class EventDispatcher {
std::vector<Callback> callbacks;
public:
void add_callback(Callback cb) {
callbacks.push_back(std::move(cb));
}
void dispatch(int value) {
for (auto& cb : callbacks) {
if (auto* func = std::get_if<std::function<void(int)>>(&cb)) {
(*func)(value);
}
}
}
void dispatch(const std::string& value) {
for (auto& cb : callbacks) {
if (auto* func = std::get_if<std::function<void(std::string)>>(&cb)) {
(*func)(value);
}
}
}
};
// 示例8:get_if安全访问
void example_get_if() {
std::variant<int, std::string> v = "hello";
// 使用get_if(不抛出异常)
if (auto* str_ptr = std::get_if<std::string>(&v)) {
std::cout << "String value: " << *str_ptr << std::endl;
}
if (auto* int_ptr = std::get_if<int>(&v)) {
std::cout << "Int value: " << *int_ptr << std::endl;
} else {
std::cout << "Not holding int" << std::endl;
}
}
// 示例9:monadic操作(C++23引入,这里模拟)
template<typename... Ts>
struct VariantWrapper {
std::variant<Ts...> var;
template<typename Func>
auto and_then(Func&& func) {
return std::visit([&func](auto&& arg) {
return func(std::forward<decltype(arg)>(arg));
}, var);
}
};
// 示例10:性能考虑
void example_performance() {
// variant使用栈内存,大小是最大类型+类型索引
std::variant<int, double, std::array<char, 100>> v;
std::cout << "Size of variant: " << sizeof(v) << " bytes" << std::endl;
// 与union比较
union TraditionalUnion {
int i;
double d;
char str[100];
};
std::cout << "Size of union: " << sizeof(TraditionalUnion) << " bytes" << std::endl;
}
int main() {
example_basic();
example_visitor();
example_error_handling();
example_get_if();
example_performance();
// 状态机示例
Connection conn;
conn.connect();
conn.print_state();
// JSON示例
JSONValue json = std::map<std::string, JSONValue>{
{"name", "John"},
{"age", 30},
{"scores", std::vector<JSONValue>{85, 90, 78}},
{"active", true}
};
std::cout << "\nJSON output:\n";
print_json(json);
std::cout << std::endl;
return 0;
}
std::string_view 详细用法
(零拷贝)string_view(零拷贝)
void print(std::string_view sv) {
std::cout << sv;
}
print("hello");
print(std::string("world"));
📌 工程价值
- 传参无拷贝
- 性能友好(日志、解析)
具体使用,如下:
c
#include <iostream>
#include <string_view>
#include <string>
#include <vector>
#include <algorithm>
#include <cstring>
// 定义:字符串的非拥有视图,只读访问,不管理内存
// 示例1:基本创建和使用
void example_basic() {
// 从C风格字符串创建
const char* cstr = "Hello, World!";
std::string_view sv1(cstr);
std::cout << "sv1: " << sv1 << ", size: " << sv1.size() << std::endl;
// 从std::string创建
std::string str = "Hello from std::string";
std::string_view sv2(str);
std::cout << "sv2: " << sv2 << std::endl;
// 从字符串字面量创建
std::string_view sv3 = "String literal";
std::cout << "sv3: " << sv3 << std::endl;
// 从子字符串创建
std::string_view sv4 = sv1.substr(0, 5); // "Hello"
std::cout << "sv4 (substr): " << sv4 << std::endl;
// 从指针和长度创建
const char* data = "Raw data";
std::string_view sv5(data, 3); // "Raw"
std::cout << "sv5 (pointer+len): " << sv5 << std::endl;
// 从数组创建
char arr[] = {'H', 'i', '!', '\0'};
std::string_view sv6(arr);
std::cout << "sv6 (array): " << sv6 << std::endl;
}
// 示例2:作为函数参数(高效,无拷贝)
void print_string(std::string_view sv) {
std::cout << "Received: " << sv
<< ", Length: " << sv.length()
<< ", Data: " << sv.data() << std::endl;
}
std::string_view find_word(std::string_view text, std::string_view word) {
size_t pos = text.find(word);
if (pos != std::string_view::npos) {
return text.substr(pos, word.length());
}
return {}; // 空string_view
}
void example_function_parameters() {
// 可以接受各种字符串类型,无拷贝
print_string("C string");
std::string str = "std::string";
print_string(str);
std::string_view sv = "string_view";
print_string(sv);
// 查找示例
std::string_view text = "The quick brown fox jumps over the lazy dog";
std::string_view found = find_word(text, "fox");
if (!found.empty()) {
std::cout << "Found: " << found << std::endl;
}
}
// 示例3:字符串操作(只读)
void example_string_operations() {
std::string_view sv = "Hello, World! Programming is fun!";
// 查找
size_t pos = sv.find("World");
if (pos != std::string_view::npos) {
std::cout << "'World' found at position: " << pos << std::endl;
}
// 比较
std::string_view sv2 = "Hello";
if (sv.compare(0, 5, sv2) == 0) {
std::cout << "Starts with 'Hello'" << std::endl;
}
// 移除前缀/后缀
std::string_view sv3 = sv;
sv3.remove_prefix(7); // 移除"Hello, "
std::cout << "After remove_prefix: " << sv3 << std::endl;
sv3.remove_suffix(19); // 移除"! Programming is fun!"
std::cout << "After remove_suffix: " << sv3 << std::endl;
// 检查是否以特定字符串开头/结尾
if (sv.starts_with("Hello")) {
std::cout << "Starts with Hello" << std::endl;
}
if (sv.ends_with("fun!")) {
std::cout << "Ends with fun!" << std::endl;
}
}
// 示例4:与标准算法结合
void example_with_algorithms() {
std::vector<std::string_view> words = {
"apple", "banana", "cherry", "date", "elderberry"
};
// 查找包含特定字符的单词
auto it = std::find_if(words.begin(), words.end(),
[](std::string_view sv) {
return sv.find('a') != std::string_view::npos;
});
if (it != words.end()) {
std::cout << "First word with 'a': " << *it << std::endl;
}
// 排序string_view(按视图排序,不修改原字符串)
std::sort(words.begin(), words.end());
std::cout << "Sorted words: ";
for (const auto& w : words) {
std::cout << w << " ";
}
std::cout << std::endl;
// 使用string_view作为map的key(需要自定义比较器或C++20)
struct StringViewCompare {
bool operator()(std::string_view a, std::string_view b) const {
return a < b;
}
};
std::map<std::string_view, int, StringViewCompare> word_count;
word_count["apple"] = 3;
word_count["banana"] = 2;
}
// 示例5:性能优势演示
#include <chrono>
void process_string(const std::string& str) {
// 有拷贝
volatile size_t len = str.length(); // 防止优化
(void)len;
}
void process_string_view(std::string_view sv) {
// 无拷贝
volatile size_t len = sv.length();
(void)len;
}
void example_performance() {
std::string long_string(10000, 'x'); // 创建长字符串
auto start1 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 10000; ++i) {
process_string(long_string); // 每次都有拷贝
}
auto end1 = std::chrono::high_resolution_clock::now();
auto start2 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 10000; ++i) {
process_string_view(long_string); // 无拷贝
}
auto end2 = std::chrono::high_resolution_clock::now();
auto time1 = std::chrono::duration_cast<std::chrono::microseconds>(end1 - start1);
auto time2 = std::chrono::duration_cast<std::chrono::microseconds>(end2 - start2);
std::cout << "std::string time: " << time1.count() << "μs" << std::endl;
std::cout << "std::string_view time: " << time2.count() << "μs" << std::endl;
std::cout << "Speedup: " << static_cast<double>(time1.count()) / time2.count()
<< "x" << std::endl;
}
// 示例6:解析和处理
std::vector<std::string_view> split_string(std::string_view str,
std::string_view delimiters) {
std::vector<std::string_view> tokens;
size_t start = 0;
size_t end = 0;
while ((end = str.find_first_of(delimiters, start)) != std::string_view::npos) {
if (end != start) {
tokens.push_back(str.substr(start, end - start));
}
start = end + 1;
}
if (start < str.length()) {
tokens.push_back(str.substr(start));
}
return tokens;
}
void example_parsing() {
std::string_view csv_line = "apple,banana,cherry,date,elderberry";
auto fruits = split_string(csv_line, ",");
std::cout << "Parsed fruits:" << std::endl;
for (const auto& fruit : fruits) {
std::cout << " - " << fruit << std::endl;
}
// 解析配置行
std::string_view config_line = "timeout = 30";
size_t eq_pos = config_line.find('=');
if (eq_pos != std::string_view::npos) {
std::string_view key = config_line.substr(0, eq_pos);
std::string_view value = config_line.substr(eq_pos + 1);
// 去除空格
key.remove_prefix(std::min(key.find_first_not_of(" "), key.size()));
key.remove_suffix(key.size() - key.find_last_not_of(" ") - 1);
value.remove_prefix(std::min(value.find_first_not_of(" "), value.size()));
value.remove_suffix(value.size() - value.find_last_not_of(" ") - 1);
std::cout << "Key: '" << key << "', Value: '" << value << "'" << std::endl;
}
}
// 示例7:注意事项和陷阱
void example_pitfalls() {
// 陷阱1:悬挂引用
std::string_view dangerous;
{
std::string temp = "temporary string";
dangerous = temp; // string_view指向临时字符串
} // temp被销毁
// 危险!dangerous现在指向已释放的内存
// std::cout << dangerous << std::endl; // 未定义行为!
// 正确做法:确保原字符串生命周期足够长
std::string permanent = "permanent string";
std::string_view safe = permanent; // 安全
// 陷阱2:不以null结尾
char buffer[] = {'H', 'e', 'l', 'l', 'o'}; // 没有null终止符
std::string_view sv(buffer, 5);
// sv.data()不能保证null终止!
// 如果需要C风格字符串,需要确保有终止符
std::string_view sv2 = "Hello";
if (sv2.data()[sv2.size()] == '\0') {
std::cout << "Properly null-terminated" << std::endl;
}
// 陷阱3:修改原字符串
char mutable_buffer[] = "Hello";
std::string_view sv3(mutable_buffer);
std::cout << "Before: " << sv3 << std::endl;
mutable_buffer[0] = 'J';
std::cout << "After: " << sv3 << std::endl; // 变为"Jello"
}
// 示例8:字符串字面量操作符(C++14引入,这里展示与string_view结合)
constexpr std::string_view operator"" _sv(const char* str, size_t len) {
return std::string_view(str, len);
}
void example_user_literal() {
auto sv = "Hello World"_sv;
static_assert(std::is_same_v<decltype(sv), std::string_view>);
std::cout << "Using literal: " << sv << ", size: " << sv.size() << std::endl;
}
// 示例9:constexpr string_view(编译期字符串处理)
constexpr std::string_view compile_time_str = "Compile time string";
constexpr bool starts_with_compile(std::string_view sv, std::string_view prefix) {
return sv.size() >= prefix.size() &&
sv.substr(0, prefix.size()) == prefix;
}
void example_constexpr() {
static_assert(compile_time_str.size() == 19);
static_assert(starts_with_compile(compile_time_str, "Compile"));
constexpr std::string_view local_constexpr = "Local constexpr";
static_assert(local_constexpr.find("const") != std::string_view::npos);
}
// 示例10:与其它类型互操作
class StringViewWrapper {
std::string_view view;
public:
// 从各种字符串类型构造
StringViewWrapper(const char* str) : view(str) {}
StringViewWrapper(const std::string& str) : view(str) {}
StringViewWrapper(std::string_view sv) : view(sv) {}
// 转换为std::string(如果需要所有权)
std::string to_string() const {
return std::string(view);
}
// 各种操作
bool contains(std::string_view substr) const {
return view.find(substr) != std::string_view::npos;
}
std::string_view substr(size_t pos, size_t count = std::string_view::npos) const {
return view.substr(pos, count);
}
friend std::ostream& operator<<(std::ostream& os, const StringViewWrapper& wrapper) {
return os << wrapper.view;
}
};
int main() {
example_basic();
example_function_parameters();
example_string_operations();
example_with_algorithms();
example_parsing();
example_pitfalls();
example_user_literal();
example_constexpr();
// 性能测试
example_performance();
// 包装器示例
StringViewWrapper wrapper1("C string");
StringViewWrapper wrapper2(std::string("std::string"));
StringViewWrapper wrapper3("string_view"sv);
std::cout << "Wrapper1: " << wrapper1 << std::endl;
std::cout << "Contains 'str': " << wrapper1.contains("str") << std::endl;
return 0;
}
std::filesystem
std::filesystem ⭐⭐⭐⭐⭐
#include <filesystem>
namespace fs = std::filesystem;
for (auto& p : fs::directory_iterator("data")) {
std::cout << p.path() << std::endl;
}
📌 工程价值(你做工程必用)
- 文件遍历、路径拼接
- 可逐步替代 Qt 的 QFileInfo(或混用)
C++20 新特性
可以把 C++20 理解为:模板更像人话 + 算法更像流水线 + 异步更像同步
一、Concepts(模板约束)
是什么
给模板加"类型条件",让错误在接口处就暴露。
以前(C++17)
cpp
template<typename T>
T add(T a, T b) {
return a + b; // 不满足会报一堆天书
}
C++20
cpp
#include <concepts>
template<std::integral T>
T add(T a, T b) {
return a + b;
}
add(1, 2); // ✅
add(1.2, 2.3); // ❌ 编译期直接拒绝
工程价值
- 模板报错瞬间"像人话"
- 写库、写算法非常爽
二、Ranges(算法 & 容器革命)
是什么
STL 算法的"组合版 + 懒执行"
示例
cpp
#include <ranges>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1,2,3,4,5,6};
auto even = v
| std::views::filter([](int x) { return x % 2 == 0; })
| std::views::transform([](int x) { return x * 10; });
for (int x : even) {
std::cout << x << " ";
}
}
// Ranges方式:惰性求值,无中间存储
auto result = numbers
| rv::filter([](int n) { return n % 2 == 0; }) // 过滤偶数
| rv::transform([](int n) { return n * n; }) // 平方
| rv::take(3); // 取前3个
工程价值
- 数据处理"管道化"
- 非常适合 UI / 数据流 / 解析逻辑
三、Coroutine(协程)(进阶)
是什么
把异步写成同步代码
极简示例(概念理解)
cpp
#include <coroutine>
struct Task {
struct promise_type {
Task get_return_object() { return {}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
};
Task foo() {
co_return;
}
工程价值
- 网络
- IO
- 后台任务
⚠️ Qt 目前更多是 concept + future + thread,协程别急
四、std::span(安全的数组视图)
是什么
非拥有的连续内存视图(安全版
T* + size)
示例
cpp
#include <span>
#include <vector>
#include <iostream>
void process(std::span<int> data) {
for (int x : data) {
std::cout << x << " ";
}
}
int main() {
std::vector<int> v = {1,2,3};
process(v); // 不拷贝
}
工程价值
- 算法函数参数首选
- 替代裸指针 + size
五、std::format(现代格式化)⭐⭐⭐⭐⭐
是什么
C++ 原生
fmt,干掉printf/ostringstream
示例
cpp
#include <format>
#include <iostream>
int main() {
int id = 10;
double value = 3.14;
std::cout << std::format("id={}, value={:.2f}", id, value);
}
工程价值
- 日志系统
- UI 文案
- 强类型、可读性高
六、std::ranges::sort 等算法升级
cpp
#include <ranges>
#include <vector>
std::vector<int> v = {4,1,3,2};
std::ranges::sort(v);
📌 不再需要:
cpp
std::sort(v.begin(), v.end());
七、三路比较 <=>(太空船运算符)
是什么
自动生成所有比较运算符
示例
cpp
#include <compare>
struct Point {
int x;
int y;
auto operator<=>(const Point&) const = default;
};
你立刻拥有:
<>==!=
工程价值
- 数据结构
- map / set key
八、consteval / constexpr 升级
是什么
更强的编译期计算
cpp
consteval int square(int x) {
return x * x;
}
int main() {
int a = square(5); // 必须编译期
}
九、std::jthread(自动 join 的线程)
是什么
RAII 线程,析构自动 join
示例
cpp
#include <thread>
#include <iostream>
void work() {
std::cout << "working\n";
}
int main() {
std::jthread t(work);
} // 自动 join
工程价值
- 防止线程泄漏
- 比 std::thread 安全
十、std::stop_token(线程取消)
cpp
#include <thread>
#include <iostream>
void work(std::stop_token st) {
while (!st.stop_requested()) {
// do work
}
}
int main() {
std::jthread t(work);
t.request_stop();
}
十一、[[...]]
cpp
if (error) [[unlikely]] {
return;
}
📌 性能提示,非保证
好,这个点问得非常专业 👍
你说的 [[...]] 不是"一个特性",而是 C++11 引入、在 C++17 / C++20 里逐步增强的一整套:
👉 标准属性(attributes)机制。
我给你来一版从底层认知 → 常用属性 → 工程实战 → 易踩坑的完整讲解。
一、[[...]] 到底是什么?
定义(人话版)
[[...]]是 给编译器看的"元信息"不改变语义,只影响:
- 编译器诊断(warning / error)
- 优化策略
- 代码意图表达
📌 核心原则:
属性不会改变程序逻辑,只是"提示 / 约束 / 标注"
二、为什么 C++ 要引入 [[...]]?
在它之前(C 风格)
cpp
__attribute__((unused))
__declspec(noreturn)
❌ 问题:
- 编译器相关
- 不可移植
- 丑
C++ 的目标
cpp
[[nodiscard]]
[[maybe_unused]]
[[likely]]
✔ 统一
✔ 可移植
✔ 可组合
三、最常用、你必须会的标准属性 ⭐⭐⭐⭐⭐
1️⃣ [[nodiscard]](最重要)
是什么
返回值不能被忽略
示例
cpp
[[nodiscard]]
int calc() {
return 42;
}
int main() {
calc(); // ⚠️ 编译警告
int x = calc(); // ✅
}
工程场景
- 错误码
- 资源句柄
std::optional / expected
📌 C++17 起支持
2️⃣ [[maybe_unused]]
是什么
消除"未使用变量 / 参数"的警告
示例
cpp
void foo([[maybe_unused]] int debugFlag) {
// debugFlag 可能在某些宏下使用
}
工程场景
- 跨平台
- Debug / Release 不同逻辑
3️⃣ [[likely]] / [[unlikely]](C++20)
是什么
告诉编译器:这个分支更可能 / 不太可能发生
示例
cpp
if (value < 0) [[unlikely]] {
return;
}
注意
- 是 提示,不是命令
- 编译器可忽略
📌 适合:
- 错误路径
- 兜底分支
4️⃣ [[fallthrough]](switch 专用)
是什么
显式允许 case 穿透
示例
cpp
switch (x) {
case 1:
doA();
[[fallthrough]];
case 2:
doB();
break;
}
📌 防止误写漏 break
5️⃣ [[deprecated]]
是什么
标记"过时接口"
示例
cpp
[[deprecated("Use newFunc instead")]]
void oldFunc() {}
调用时编译器会警告。
📌 工程价值:
- 平滑重构
- API 演进
四、属性可以用在哪里?
属性不是随便放的,它有作用域:
cpp
[[nodiscard]] int foo(); // 函数
[[deprecated]] struct A {}; // 类型
void bar([[maybe_unused]] int); // 参数
[[likely]] if (...) {} // 语句
五、属性 ≠ 宏(这是重点)
对比
| 属性 | 宏 |
|---|---|
| 作用于语法层 | 文本替换 |
| 有作用域 | 无作用域 |
| 可被工具识别 | 不易分析 |
| 标准化 | 编译器私有 |
👉 能用 [[...]],别用宏
六、编译器相关属性(了解即可)
cpp
[[gnu::unused]]
[[msvc::noinline]]
示例
cpp
[[gnu::unused]] int x;
📌 命名空间隔离,不冲突
七、你工程里可以"立刻用起来"的组合
1️⃣ 返回值强制检查
cpp
[[nodiscard]]
bool loadConfig();
2️⃣ 错误路径优化
cpp
if (!ptr) [[unlikely]] {
return;
}
3️⃣ 安全 switch
cpp
switch (state) {
case A:
...
[[fallthrough]];
case B:
...
}
4️⃣ 渐进式重构
cpp
[[deprecated("Use NewApi")]]
void OldApi(); // 这段话可能过时,不去使用
八、容易踩的坑(一定要知道)
❌ 属性不会改变逻辑
cpp
[[nodiscard]] int x = 10; // ❌ 没意义
❌ likely 不是性能魔法
cpp
if (hotPath) [[likely]] { ... }
👉 编译器可能忽略
❌ 属性不是注释
cpp
[[deprecated]] // 不等于注释
九、总结一句"工程级理解"
[[...]]是 写给"编译器 + 未来维护者"的注释不是给机器跑逻辑的
十二、std::remove_cvref_t
cpp
using T = std::remove_cvref_t<decltype(arg)>;
👉 替代 std::decay_t 的常见用途
十三、constexpr 容器(重要但低调)
cpp
constexpr std::vector<int> make() {
return {1,2,3};
}