1.2. 现代 C++ 特性速览

本节快速介绍 C++11 到 C++23 的重要新特性。

1.2.1. C++11 核心特性

1.2.1.1. auto 类型推导

// 基础用法
auto x = 42;            // int
auto y = 3.14;          // double
auto s = "hello"s;      // std::string (需要 using namespace std::literals)

// 迭代器简化
std::map<std::string, std::vector<int>> data;
auto it = data.begin();  // 代替冗长的类型声明

// 注意:auto 会去掉引用和 const
const int& ref = x;
auto a = ref;           // int,不是 const int&
auto& b = ref;          // const int&
decltype(auto) c = ref; // const int& (C++14)

1.2.1.2. Lambda 表达式

// 基础语法
auto add = [](int a, int b) { return a + b; };

// 捕获列表
int factor = 2;
auto multiply = [factor](int x) { return x * factor; };   // 值捕获
auto modify = [&factor](int x) { factor = x; };           // 引用捕获
auto all_by_value = [=](int x) { return x * factor; };    // 全部值捕获
auto all_by_ref = [&](int x) { factor = x; };             // 全部引用捕获

// 陷阱:引用捕获悬空
std::function<int()> create_counter() {
    int count = 0;
    return [&count]() { return ++count; };  // 危险!count 已销毁
}

1.2.1.3. 移动语义与右值引用

class Buffer {
    int* data;
    size_t size;
public:
    // 移动构造函数
    Buffer(Buffer&& other) noexcept 
        : data(other.data), size(other.size) {
        other.data = nullptr;
        other.size = 0;
    }
    
    // 移动赋值运算符
    Buffer& operator=(Buffer&& other) noexcept {
        if (this != &other) {
            delete[] data;
            data = other.data;
            size = other.size;
            other.data = nullptr;
            other.size = 0;
        }
        return *this;
    }
};

// 使用 std::move
Buffer b1(1024);
Buffer b2 = std::move(b1);  // b1 被"掏空"

1.2.1.4. 智能指针

#include <memory>

// unique_ptr: 独占所有权
auto up = std::make_unique<int>(42);  // C++14
// auto up2 = up;  // 编译错误!
auto up2 = std::move(up);  // OK

// shared_ptr: 共享所有权
auto sp = std::make_shared<int>(42);
auto sp2 = sp;  // OK,引用计数 +1
std::cout << sp.use_count();  // 2

// weak_ptr: 弱引用,不增加引用计数
std::weak_ptr<int> wp = sp;
if (auto locked = wp.lock()) {  // 尝试获取 shared_ptr
    std::cout << *locked;
}

1.2.2. C++14 新特性

1.2.2.1. 泛型 Lambda

// 参数使用 auto
auto generic_add = [](auto a, auto b) { return a + b; };
generic_add(1, 2);      // int
generic_add(1.0, 2.0);  // double
generic_add("a"s, "b"s);// string

1.2.2.2. 返回类型推导

auto factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);  // 编译器推导返回类型
}

1.2.2.3. 变量模板

template<typename T>
constexpr T pi = T(3.14159265358979323846);

double area = pi<double> * r * r;
float areaf = pi<float> * r * r;

1.2.3. C++17 新特性

1.2.3.1. 结构化绑定

// 数组
int arr[] = {1, 2, 3};
auto [a, b, c] = arr;

// pair/tuple
auto [key, value] = std::make_pair(1, "hello");

// 结构体
struct Point { int x, y; };
Point p{10, 20};
auto [x, y] = p;

// map 遍历
std::map<std::string, int> scores;
for (const auto& [name, score] : scores) {
    std::cout << name << ": " << score << "\n";
}

1.2.3.2. if/switch 初始化

// if with initializer
if (auto it = map.find(key); it != map.end()) {
    // 使用 it
}  // it 超出作用域

// switch with initializer
switch (auto val = get_value(); val) {
    case 1: /* ... */ break;
    case 2: /* ... */ break;
}

1.2.3.3. std::optional

#include <optional>

std::optional<int> find_value(int key) {
    if (/* found */) return value;
    return std::nullopt;  // 或 {}
}

if (auto result = find_value(42)) {
    std::cout << *result;
}

// 带默认值
int val = find_value(42).value_or(-1);

1.2.3.4. std::variant

#include <variant>

std::variant<int, double, std::string> v;
v = 42;
v = 3.14;
v = "hello";

// 访问
std::cout << std::get<std::string>(v);

// 安全访问
if (auto* p = std::get_if<int>(&v)) {
    std::cout << *p;
}

// 访问者模式
std::visit([](auto&& arg) {
    std::cout << arg;
}, v);

1.2.4. C++20 新特性

1.2.4.1. 概念 (Concepts)

#include <concepts>

// 定义概念
template<typename T>
concept Addable = requires(T a, T b) {
    { a + b } -> std::convertible_to<T>;
};

// 使用概念
template<Addable T>
T add(T a, T b) { return a + b; }

// 或使用 requires 子句
template<typename T>
    requires std::integral<T>
T square(T x) { return x * x; }

// 简写语法
void print(std::integral auto value) {
    std::cout << value;
}

1.2.4.2. Ranges

#include <ranges>
#include <vector>

std::vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// 链式操作
auto result = vec 
    | std::views::filter([](int n) { return n % 2 == 0; })
    | std::views::transform([](int n) { return n * n; })
    | std::views::take(3);

for (int n : result) {
    std::cout << n << " ";  // 4 16 36
}

1.2.4.3. 三路比较运算符 (Spaceship Operator)

#include <compare>

struct Point {
    int x, y;
    
    // 自动生成所有比较运算符
    auto operator<=>(const Point&) const = default;
};

Point p1{1, 2}, p2{1, 3};
if (p1 < p2) { /* ... */ }   // 自动可用
if (p1 == p2) { /* ... */ }  // 自动可用

1.2.4.4. 协程

#include <coroutine>

// 简单的生成器
generator<int> iota(int start, int end) {
    for (int i = start; i < end; ++i) {
        co_yield i;
    }
}

for (int n : iota(1, 10)) {
    std::cout << n << " ";
}

1.2.5. C++23 新特性预览

1.2.5.1. std::expected

#include <expected>

std::expected<int, std::string> parse(std::string_view s) {
    if (/* valid */) return value;
    return std::unexpected("parse error");
}

auto result = parse("42");
if (result) {
    std::cout << *result;
} else {
    std::cerr << result.error();
}

1.2.5.2. std::print

#include <print>

// 类似 Python 的 print
std::print("Hello, {}!\n", "World");
std::println("Value: {}", 42);  // 自动换行

1.2.5.3. Deducing this

struct Widget {
    // 显式 this 参数
    template<typename Self>
    auto& get_value(this Self&& self) {
        return std::forward<Self>(self).value;
    }
};

备注

建议逐步采用新特性,确保团队和编译器都支持。 使用特性检测宏 __cpp_xxx 进行条件编译。