C++现代特性Skill cpp-modern-features

这个技能用于掌握从C++11到C++23的现代C++编程特性,包括自动类型推断、lambda表达式、智能指针、移动语义、结构化绑定、概念、范围等,帮助开发者编写高效、表达性强、可维护的代码。关键词:C++,现代特性,编程,lambda,移动语义,智能指针,编译时评估,概念,范围。

后端开发 0 次安装 0 次浏览 更新于 3/25/2026

name: cpp-modern-features user-invocable: false description: 当处理需要C++11到C++23特性的现代C++代码库时使用,包括lambda、移动语义、范围、和概念。 allowed-tools:

  • Bash
  • Read
  • Write
  • Edit

C++现代特性

掌握从C++11到C++23的现代C++特性,包括lambda、移动语义、范围、概念和编译时评估。这个技能使您能够编写高效、表达性强、可维护的现代C++代码。

C++11特性

自动类型推断

auto 关键字启用自动类型推断,减少冗长并提高可维护性:

// 传统方式
std::vector<int>::iterator it = vec.begin();
std::map<std::string, std::vector<int>>::const_iterator map_it = mymap.find("key");

// 现代C++11
auto it = vec.begin();
auto map_it = mymap.find("key");

// 带初始化的auto
auto value = 42;              // int
auto pi = 3.14;              // double
auto name = std::string("Alice"); // std::string
auto lambda = [](int x) { return x * 2; }; // lambda类型

基于范围的for循环

简化容器和数组的迭代:

std::vector<int> numbers = {1, 2, 3, 4, 5};

// 传统循环
for (std::vector<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {
    std::cout << *it << " ";
}

// 基于范围的for(C++11)
for (int num : numbers) {
    std::cout << num << " ";
}

// 使用引用修改元素
for (int& num : numbers) {
    num *= 2;
}

// 使用const引用提高效率
for (const auto& str : string_vector) {
    process(str);
}

Lambda表达式

具有捕获功能的匿名函数:

// 基本lambda
auto add = [](int a, int b) { return a + b; };
int result = add(3, 4); // 7

// 带捕获的lambda
int multiplier = 10;
auto multiply = [multiplier](int x) { return x * multiplier; };

// 通过引用捕获
int counter = 0;
auto increment = [&counter]() { counter++; };

// 通过值捕获所有
auto func1 = [=]() { return x + y + z; };

// 通过引用捕获所有
auto func2 = [&]() { x++; y++; };

// 混合捕获
auto func3 = [&sum, multiplier](int x) { sum += x * multiplier; };

// 可变lambda(可以修改捕获的值)
auto mutable_func = [counter]() mutable { return counter++; };

智能指针

使用RAII自动内存管理:

#include <memory>

// unique_ptr - 独占所有权
std::unique_ptr<int> ptr1 = std::make_unique<int>(42);
std::unique_ptr<MyClass> obj = std::make_unique<MyClass>(arg1, arg2);

// shared_ptr - 共享所有权,带引用计数
std::shared_ptr<int> ptr2 = std::make_shared<int>(100);
std::shared_ptr<int> ptr3 = ptr2; // 引用计数 = 2

// weak_ptr - 非拥有引用
std::weak_ptr<int> weak = ptr2;
if (auto locked = weak.lock()) {
    // 安全使用锁定指针
    std::cout << *locked << std::endl;
}

// 自定义删除器
auto deleter = [](FILE* fp) { fclose(fp); };
std::unique_ptr<FILE, decltype(deleter)> file(fopen("data.txt", "r"), deleter);

Nullptr

类型安全的空指针常量:

// 旧方式(模糊)
void func(int x);
void func(char* ptr);
func(NULL); // 哪个重载?取决于NULL定义

// 现代方式(明确)
func(nullptr); // 明确调用func(char*)

// 智能指针初始化
std::unique_ptr<int> ptr = nullptr;
if (ptr != nullptr) {
    // 使用ptr
}

C++14特性

泛型Lambda

auto参数的lambda:

// 泛型lambda(C++14)
auto generic_add = [](auto a, auto b) { return a + b; };

int sum1 = generic_add(3, 4);           // 适用于int
double sum2 = generic_add(3.14, 2.71);  // 适用于double
std::string concat = generic_add(std::string("Hello"), std::string(" World"));

// 多个auto参数
auto compare = [](auto a, auto b) { return a < b; };

// 在算法中使用
std::vector<int> vec = {5, 2, 8, 1, 9};
std::sort(vec.begin(), vec.end(), [](auto a, auto b) { return a > b; });

返回类型推断

函数的自动返回类型:

// C++14: auto返回类型推断
auto multiply(int a, int b) {
    return a * b; // 返回类型推断为int
}

auto get_vector() {
    return std::vector<int>{1, 2, 3}; // 推断为std::vector<int>
}

// 多个返回语句必须具有相同类型
auto conditional(bool flag) {
    if (flag)
        return 42;    // int
    else
        return 100;   // int - 正确
    // return 3.14;  // 错误:类型不同
}

Make Unique

unique_ptr的工厂函数:

// C++11需要手动构造
std::unique_ptr<MyClass> ptr1(new MyClass(arg1, arg2));

// C++14提供std::make_unique
auto ptr2 = std::make_unique<MyClass>(arg1, arg2);

// 异常安全性优势
func(std::unique_ptr<int>(new int(1)), std::unique_ptr<int>(new int(2))); // 有风险
func(std::make_unique<int>(1), std::make_unique<int>(2)); // 安全

C++17特性

结构化绑定

将对象分解为单个变量:

// 对和元组
std::pair<int, std::string> get_data() {
    return {42, "Answer"};
}

auto [id, name] = get_data();
std::cout << id << ": " << name << std::endl;

// 映射
std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}};
for (const auto& [name, score] : scores) {
    std::cout << name << " scored " << score << std::endl;
}

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

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

If Constexpr

编译时条件语句:

template<typename T>
auto process(T value) {
    if constexpr (std::is_integral_v<T>) {
        return value * 2;
    } else if constexpr (std::is_floating_point_v<T>) {
        return value * 3.14;
    } else {
        return value;
    }
}

int result1 = process(10);      // 返回20
double result2 = process(2.0);  // 返回6.28

折叠表达式

可变参数模板操作:

// 求和所有参数
template<typename... Args>
auto sum(Args... args) {
    return (args + ...);
}

int total = sum(1, 2, 3, 4, 5); // 15

// 打印所有参数
template<typename... Args>
void print(Args... args) {
    (std::cout << ... << args) << std::endl;
}

print("Value: ", 42, " ", 3.14); // Value: 42 3.14

// 逻辑操作
template<typename... Args>
bool all_true(Args... args) {
    return (... && args);
}

bool result = all_true(true, true, false); // false

Std::optional

类型安全的可选值:

#include <optional>

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::vector<int> numbers = {1, 2, 3, 4, 5};
if (auto result = find_value(numbers, 3)) {
    std::cout << "Found: " << *result << std::endl;
} else {
    std::cout << "Not found" << std::endl;
}

// value_or用于默认值
int value = find_value(numbers, 10).value_or(-1);

Std::variant

类型安全的联合:

#include <variant>

std::variant<int, double, std::string> data;

data = 42;
data = 3.14;
data = std::string("Hello");

// 访问模式
std::visit([](auto&& arg) {
    using T = std::decay_t<decltype(arg)>;
    if constexpr (std::is_same_v<T, int>) {
        std::cout << "int: " << arg << std::endl;
    } else if constexpr (std::is_same_v<T, double>) {
        std::cout << "double: " << arg << std::endl;
    } else {
        std::cout << "string: " << arg << std::endl;
    }
}, data);

// 获取值
if (auto* str = std::get_if<std::string>(&data)) {
    std::cout << *str << std::endl;
}

C++20特性

概念

约束模板参数:

#include <concepts>

// 定义概念
template<typename T>
concept Numeric = std::is_arithmetic_v<T>;

// 使用概念约束模板
template<Numeric T>
T add(T a, T b) {
    return a + b;
}

// 带requires子句的概念
template<typename T>
concept Hashable = requires(T a) {
    { std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
};

// 多个约束
template<typename T>
concept Sortable = std::copyable<T> && requires(T a, T b) {
    { a < b } -> std::convertible_to<bool>;
};

// 在函数中使用
template<Sortable T>
void sort_data(std::vector<T>& vec) {
    std::sort(vec.begin(), vec.end());
}

范围

可组合的算法和视图:

#include <ranges>

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

// 使用视图过滤和转换
auto result = numbers
    | std::views::filter([](int n) { return n % 2 == 0; })
    | std::views::transform([](int n) { return n * n; });

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

// 取前N个元素
auto first_five = numbers | std::views::take(5);

// 反向视图
auto reversed = numbers | std::views::reverse;

// 链接多个操作
auto complex_view = numbers
    | std::views::filter([](int n) { return n > 3; })
    | std::views::transform([](int n) { return n * 2; })
    | std::views::take(3);

协程

协作式多任务:

#include <coroutine>
#include <iostream>

// 简单生成器
struct Generator {
    struct promise_type {
        int current_value;

        Generator get_return_object() {
            return Generator{std::coroutine_handle<promise_type>::from_promise(*this)};
        }

        std::suspend_always initial_suspend() { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        std::suspend_always yield_value(int value) {
            current_value = value;
            return {};
        }

        void return_void() {}
        void unhandled_exception() {}
    };

    std::coroutine_handle<promise_type> handle;

    Generator(std::coroutine_handle<promise_type> h) : handle(h) {}
    ~Generator() { if (handle) handle.destroy(); }

    int value() { return handle.promise().current_value; }
    bool next() {
        handle.resume();
        return !handle.done();
    }
};

Generator counter(int start, int end) {
    for (int i = start; i < end; ++i) {
        co_yield i;
    }
}

// 使用
auto gen = counter(0, 5);
while (gen.next()) {
    std::cout << gen.value() << " ";
}

三路比较(飞船操作符)

简化的比较操作符:

#include <compare>

struct Point {
    int x, y;

    // 单个操作符生成所有六个比较操作符
    auto operator<=>(const Point& other) const = default;
};

Point p1{1, 2};
Point p2{1, 3};

bool eq = (p1 == p2);  // false
bool lt = (p1 < p2);   // true
bool gt = (p1 > p2);   // false

// 自定义飞船操作符
struct Person {
    std::string name;
    int age;

    auto operator<=>(const Person& other) const {
        if (auto cmp = name <=> other.name; cmp != 0)
            return cmp;
        return age <=> other.age;
    }
};

C++23特性预览

Std::expected

无异常的错误处理:

#include <expected>

std::expected<int, std::string> divide(int a, int b) {
    if (b == 0) {
        return std::unexpected("Division by zero");
    }
    return a / b;
}

// 使用
auto result = divide(10, 2);
if (result) {
    std::cout << "Result: " << *result << std::endl;
} else {
    std::cout << "Error: " << result.error() << std::endl;
}

// 转换和错误处理
auto transformed = divide(20, 4)
    .transform([](int x) { return x * 2; })
    .or_else([](auto error) {
        std::cout << "Error: " << error << std::endl;
        return std::expected<int, std::string>(0);
    });

If with Initializer Enhancement

// C++23: if with pattern matching improvements
std::map<int, std::string> map = {{1, "one"}, {2, "two"}};

if (auto [it, inserted] = map.insert({3, "three"}); inserted) {
    std::cout << "Inserted: " << it->second << std::endl;
}

// Enhanced static constexpr if
template<typename T>
void process(T value) {
    if constexpr (requires { value.size(); }) {
        std::cout << "Size: " << value.size() << std::endl;
    }
}

移动语义

右值引用

class Buffer {
    char* data;
    size_t size;

public:
    // 构造函数
    Buffer(size_t s) : size(s), data(new char[s]) {}

    // 复制构造函数
    Buffer(const Buffer& other) : size(other.size), data(new char[size]) {
        std::copy(other.data, other.data + size, data);
    }

    // 移动构造函数
    Buffer(Buffer&& other) noexcept : size(other.size), data(other.data) {
        other.data = nullptr;
        other.size = 0;
    }

    // 复制赋值
    Buffer& operator=(const Buffer& other) {
        if (this != &other) {
            delete[] data;
            size = other.size;
            data = new char[size];
            std::copy(other.data, other.data + size, data);
        }
        return *this;
    }

    // 移动赋值
    Buffer& operator=(Buffer&& other) noexcept {
        if (this != &other) {
            delete[] data;
            data = other.data;
            size = other.size;
            other.data = nullptr;
            other.size = 0;
        }
        return *this;
    }

    ~Buffer() { delete[] data; }
};

Std::move 和完美转发

#include <utility>

// 使用std::move
std::vector<int> vec1 = {1, 2, 3, 4, 5};
std::vector<int> vec2 = std::move(vec1); // vec1现在为空

// 完美转发
template<typename T>
void wrapper(T&& arg) {
    // 转发arg保留其值类别
    process(std::forward<T>(arg));
}

// 带完美转发的工厂函数
template<typename T, typename... Args>
std::unique_ptr<T> make_unique_custom(Args&&... args) {
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

// Emplace方法使用完美转发
std::vector<std::pair<int, std::string>> vec;
vec.emplace_back(1, "one"); // 原地构造

Lambda高级特性

递归Lambda

// C++14及以后
auto fibonacci = [](int n) {
    auto impl = [](int n, auto& self) -> int {
        if (n <= 1) return n;
        return self(n-1, self) + self(n-2, self);
    };
    return impl(n, impl);
};

// C++23: Deducing this
auto fibonacci_cpp23 = [](this auto self, int n) -> int {
    if (n <= 1) return n;
    return self(n-1) + self(n-2);
};

Init Captures (C++14)

// 仅移动类型在捕获中
auto ptr = std::make_unique<int>(42);
auto lambda = [p = std::move(ptr)]() {
    std::cout << *p << std::endl;
};

// 在捕获中初始化新变量
auto lambda2 = [value = computeExpensiveValue()]() {
    return value * 2;
};

// 多个init捕获
auto lambda3 = [x = getValue(), y = getOtherValue()]() {
    return x + y;
};

编译时评估

Constexpr函数

// C++11 constexpr(有限)
constexpr int factorial_cpp11(int n) {
    return (n <= 1) ? 1 : n * factorial_cpp11(n - 1);
}

// C++14 constexpr(更强大)
constexpr int factorial(int n) {
    int result = 1;
    for (int i = 2; i <= n; ++i) {
        result *= i;
    }
    return result;
}

constexpr int value = factorial(5); // 在编译时计算

// C++20 constexpr with std::vector
constexpr auto compute_primes(int max) {
    std::vector<int> primes;
    for (int i = 2; i < max; ++i) {
        bool is_prime = true;
        for (int p : primes) {
            if (i % p == 0) {
                is_prime = false;
                break;
            }
        }
        if (is_prime) primes.push_back(i);
    }
    return primes;
}

Consteval (C++20)

必须在编译时评估的函数:

consteval int square(int n) {
    return n * n;
}

constexpr int value1 = square(5); // 正确:编译时
// int x = 5;
// int value2 = square(x); // 错误:必须在编译时

// Consteval with constexpr
constexpr int maybe_compile_time(int n) {
    if (std::is_constant_evaluated()) {
        return n * n;
    } else {
        return n + n;
    }
}

最佳实践

  1. 优先使用auto处理复杂类型:使用auto避免冗长的类型声明,特别是迭代器和lambda
  2. 尽可能使用基于范围的for:意图更清晰,比传统循环更少错误
  3. 优先使用lambda处理简单操作:特别是在算法调用如std::transformstd::for_each
  4. 使用智能指针进行所有权管理:优先使用unique_ptrshared_ptr处理拥有的资源,而非原始指针
  5. 拥抱移动语义:为资源拥有类型实现移动构造函数/赋值
  6. 使用结构化绑定:使处理对、元组和映射时的代码更可读
  7. 优先使用std::optional而非特殊值:使用std::optional代替像-1或nullptr这样的哨兵值
  8. 使用概念约束模板(C++20):使模板错误更清晰并记录需求
  9. 利用范围和视图(C++20):比传统算法更具可组合性和效率
  10. 使用constexpr进行编译时计算:在可能时将计算移至编译时以提高性能

常见陷阱

  1. 使用auto时的悬空引用auto&可能创建对临时对象的悬空引用
  2. 在lambda中通过引用捕获:引用捕获可能超过捕获变量的生命周期
  3. 从const对象移动std::move在const对象上实际上不会移动
  4. 默认捕获[=]或[&]:可能意外捕获超出意图的内容
  5. 忘记标记移动操作为noexcept:阻止容器中的某些优化
  6. 使用对象后使用std::move:移动后的对象处于有效但未指定状态
  7. 基于范围的for与临时对象:容器临时对象在循环体之前被销毁
  8. 访问optional值而未检查:使用*value()而未验证has_value()
  9. 访问variant而未检查std::get在类型错误时抛出;使用get_if或访问者
  10. 过度使用auto:可能隐藏重要类型信息;需谨慎使用

何时使用

在以下情况使用此技能:

  • 处理现代C++代码库(C++11及以后)
  • 重构遗留代码以使用现代特性
  • 使用RAII实现资源管理
  • 使用模板和lambda编写泛型代码
  • 使用移动语义优化性能
  • 实现类型安全的optional或variant类型
  • 处理范围和函数式风格算法
  • 创建编译时计算的值
  • 应用概念约束模板
  • 学习或教授现代C++实践

资源