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

这个技能用于掌握和应用现代C++(C++11/14/17/20)的关键特性,如自动类型推断、lambda表达式、范围for循环、移动语义、概念和范围库,以编写更高效、更安全、更表达性强的C++代码。适用于后端开发、游戏开发、嵌入式软件等多种软件开发场景。关键词:C++,现代C++,编程特性,代码优化,软件开发。

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

名称: cpp-modern-features 用户可调用: false 描述: 当使用现代C++特性(C++11/14/17/20),包括auto、lambdas、range-based loops、structured bindings和concepts时使用。 允许工具:

  • 读取
  • 写入
  • 编辑
  • 搜索
  • 全局
  • Bash

现代C++特性

现代C++(C++11及以后)引入了重大改进,使C++更具表达性、更安全、更易用。此技能涵盖关键的现代特性,包括类型推断、lambda表达式、范围for循环、智能初始化以及最新的C++20新增内容。

自动类型推断

auto关键字启用自动类型推导,减少冗余,同时保持类型安全。

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

void auto_examples() {
    // 简单类型推断
    auto x = 42;              // int
    auto pi = 3.14159;        // double
    auto name = "Alice";      // const char*
    auto message = std::string("Hello");  // std::string

    // 迭代器简化
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    // C++11之前
    for (std::vector<int>::iterator it = numbers.begin();
         it != numbers.end(); ++it) {
        std::cout << *it << " ";
    }

    // 使用auto
    for (auto it = numbers.begin(); it != numbers.end(); ++it) {
        std::cout << *it << " ";
    }

    // 复杂类型
    std::map<std::string, std::vector<int>> data;
    auto it = data.find("key");  // 比完整类型更清晰

    // 返回类型推导 (C++14)
    auto multiply = [](int a, int b) { return a * b; };

    // 结构化绑定 (C++17)
    std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}};
    for (const auto& [name, score] : scores) {
        std::cout << name << ": " << score << "
";
    }
}

Lambda表达式

Lambdas提供内联匿名函数,对现代C++算法和回调至关重要。

#include <algorithm>
#include <vector>
#include <functional>
#include <iostream>

void lambda_examples() {
    std::vector<int> numbers = {5, 2, 8, 1, 9, 3};

    // 基本lambda
    auto print = [](int n) { std::cout << n << " "; };
    std::for_each(numbers.begin(), numbers.end(), print);

    // 带捕获的lambda
    int threshold = 5;
    auto above_threshold = [threshold](int n) { return n > threshold; };

    // 按值捕获 [=]
    auto sum_above = [=]() {
        int sum = 0;
        for (int n : numbers) {
            if (n > threshold) sum += n;
        }
        return sum;
    };

    // 按引用捕获 [&]
    int count = 0;
    auto count_above = [&count, threshold](int n) {
        if (n > threshold) count++;
    };
    std::for_each(numbers.begin(), numbers.end(), count_above);

    // 通用lambda (C++14)
    auto generic_print = [](const auto& item) {
        std::cout << item << " ";
    };

    // Lambda作为比较器
    std::sort(numbers.begin(), numbers.end(),
              [](int a, int b) { return a > b; });  // 降序

    // 可变lambda
    auto counter = [count = 0]() mutable {
        return ++count;
    };

    std::cout << counter() << "
";  // 1
    std::cout << counter() << "
";  // 2
}

// 返回lambda
std::function<int(int)> make_multiplier(int factor) {
    return [factor](int n) { return n * factor; };
}

范围for循环

范围for循环提供对容器和范围的简洁、安全迭代。

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

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

    // 基本迭代
    for (int n : numbers) {
        std::cout << n << " ";
    }

    // 按引用(用于修改)
    for (int& n : numbers) {
        n *= 2;
    }

    // 按常量引用(对大对象高效)
    std::vector<std::string> names = {"Alice", "Bob", "Charlie"};
    for (const auto& name : names) {
        std::cout << name << "
";
    }

    // 带结构化绑定 (C++17)
    std::map<std::string, int> ages = {
        {"Alice", 30},
        {"Bob", 25},
        {"Charlie", 35}
    };

    for (const auto& [name, age] : ages) {
        std::cout << name << " is " << age << " years old
";
    }

    // for循环中的初始化器 (C++20)
    for (std::vector<int> temp = {1, 2, 3}; auto n : temp) {
        std::cout << n << " ";
    }
}

// 自定义范围支持
class Range {
    int start_, end_;

public:
    Range(int start, int end) : start_(start), end_(end) {}

    struct Iterator {
        int current;
        Iterator(int val) : current(val) {}
        int operator*() const { return current; }
        Iterator& operator++() { ++current; return *this; }
        bool operator!=(const Iterator& other) const {
            return current != other.current;
        }
    };

    Iterator begin() const { return Iterator(start_); }
    Iterator end() const { return Iterator(end_); }
};

void use_custom_range() {
    for (int i : Range(0, 10)) {
        std::cout << i << " ";
    }
}

统一初始化

使用大括号的统一初始化提供一致的语法并防止窄化转换。

#include <vector>
#include <string>
#include <map>

struct Point {
    int x, y;
};

void uniform_initialization() {
    // 内置类型
    int a{42};
    double pi{3.14159};

    // 容器
    std::vector<int> numbers{1, 2, 3, 4, 5};
    std::map<std::string, int> ages{
        {"Alice", 30},
        {"Bob", 25}
    };

    // 聚合体
    Point p{10, 20};

    // 防止窄化
    // int x{3.14};  // 编译错误!
    int x = 3.14;    // 编译通过(隐式转换)

    // 空初始化(零/默认)
    int zero{};      // 0
    std::string empty{};  // ""

    // 返回值
    auto get_numbers = []() { return std::vector<int>{1, 2, 3}; };
}

// 最令人烦恼的解析解决
class Widget {
public:
    Widget() = default;
    Widget(int x) {}
};

void vexing_parse() {
    // C++11之前:声明一个函数!
    // Widget w();

    // 现代C++:创建一个对象
    Widget w{};     // 正确
    Widget w2{10};  // 也正确
}

移动语义和右值引用

移动语义实现资源的高效转移而无需复制,对性能至关重要。

#include <vector>
#include <string>
#include <utility>
#include <iostream>

class Buffer {
    size_t size_;
    int* data_;

public:
    // 构造函数
    Buffer(size_t size) : size_(size), data_(new int[size]) {
        std::cout << "Constructor
";
    }

    // 复制构造函数
    Buffer(const Buffer& other)
        : size_(other.size_), data_(new int[other.size_]) {
        std::copy(other.data_, other.data_ + size_, data_);
        std::cout << "Copy constructor
";
    }

    // 移动构造函数
    Buffer(Buffer&& other) noexcept
        : size_(other.size_), data_(other.data_) {
        other.size_ = 0;
        other.data_ = nullptr;
        std::cout << "Move constructor
";
    }

    // 复制赋值
    Buffer& operator=(const Buffer& other) {
        if (this != &other) {
            delete[] data_;
            size_ = other.size_;
            data_ = new int[size_];
            std::copy(other.data_, other.data_ + size_, data_);
            std::cout << "Copy assignment
";
        }
        return *this;
    }

    // 移动赋值
    Buffer& operator=(Buffer&& other) noexcept {
        if (this != &other) {
            delete[] data_;
            size_ = other.size_;
            data_ = other.data_;
            other.size_ = 0;
            other.data_ = nullptr;
            std::cout << "Move assignment
";
        }
        return *this;
    }

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

void move_semantics_example() {
    Buffer b1(100);
    Buffer b2 = std::move(b1);  // 移动,而非复制

    std::vector<Buffer> buffers;
    buffers.push_back(Buffer(50));  // 使用移动构造函数

    // 完美转发
    auto make_buffer = [](auto&&... args) {
        return Buffer(std::forward<decltype(args)>(args)...);
    };
}

可变模板

可变模板使函数和类能接受任意数量的参数。

#include <iostream>
#include <string>

// 基本情况
void print() {
    std::cout << "
";
}

// 递归可变模板
template<typename T, typename... Args>
void print(T first, Args... rest) {
    std::cout << first << " ";
    print(rest...);
}

// 折叠表达式 (C++17)
template<typename... Args>
auto sum(Args... args) {
    return (args + ...);
}

template<typename... Args>
auto sum_with_init(Args... args) {
    return (args + ... + 0);
}

// 完美转发与可变模板
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)...));
}

void variadic_examples() {
    print(1, 2.5, "hello", std::string("world"));

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

    // 折叠表达式用于各种操作
    auto all_true = [](auto... args) {
        return (args && ...);
    };

    auto any_true = [](auto... args) {
        return (args || ...);
    };
}

结构化绑定 (C++17)

结构化绑定将对象分解为其组成部分,提高代码可读性。

#include <tuple>
#include <map>
#include <string>
#include <array>

struct Person {
    std::string name;
    int age;
    double salary;
};

std::tuple<int, std::string, double> get_employee() {
    return {42, "Alice", 75000.0};
}

void structured_bindings() {
    // 元组分解
    auto [id, name, salary] = get_employee();

    // 对分解
    std::pair<int, std::string> p{1, "one"};
    auto [num, text] = p;

    // 结构体分解
    Person person{"Bob", 30, 80000.0};
    auto [pname, page, psalary] = person;

    // 数组分解
    std::array<int, 3> arr{1, 2, 3};
    auto [a, b, c] = arr;

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

    // 引用
    auto& [rname, rage, rsalary] = person;
    rage = 31;  // 修改person.age
}

概念 (C++20)

概念约束模板参数,提供更好的错误消息和更清晰的接口。

#include <concepts>
#include <iostream>
#include <vector>

// 定义自定义概念
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;

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

// 带多个约束的概念
template<typename T>
concept Printable = requires(T t) {
    { std::cout << t } -> std::convertible_to<std::ostream&>;
};

template<Printable T>
void print(const T& value) {
    std::cout << value << "
";
}

// 范围概念
template<typename T>
concept Range = requires(T r) {
    r.begin();
    r.end();
};

template<Range R>
void print_range(const R& range) {
    for (const auto& item : range) {
        std::cout << item << " ";
    }
    std::cout << "
";
}

// 带关联类型的概念
template<typename T>
concept Container = requires(T c) {
    typename T::value_type;
    typename T::iterator;
    { c.begin() } -> std::same_as<typename T::iterator>;
    { c.end() } -> std::same_as<typename T::iterator>;
    { c.size() } -> std::convertible_to<std::size_t>;
};

template<Container C>
void process_container(const C& container) {
    std::cout << "Size: " << container.size() << "
";
}

void concepts_example() {
    auto result = add(5, 10);      // 正确
    auto dresult = add(5.5, 2.3);  // 正确
    // auto sresult = add("hi", "there");  // 错误:不满足Numeric概念

    print(42);
    print("Hello");

    std::vector<int> vec{1, 2, 3};
    print_range(vec);
    process_container(vec);
}

范围库 (C++20)

范围库提供可组合的算法和视图,用于处理序列。

#include <ranges>
#include <vector>
#include <iostream>
#include <algorithm>

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

    // 视图是惰性的且可组合的
    auto even = [](int n) { return n % 2 == 0; };
    auto square = [](int n) { return n * n; };

    // 无需中间容器组合操作
    auto result = numbers
        | std::views::filter(even)
        | std::views::transform(square)
        | std::views::take(3);

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

    // 范围算法
    std::ranges::sort(numbers, std::greater{});

    // 带投影的查找
    struct Person {
        std::string name;
        int age;
    };

    std::vector<Person> people{
        {"Alice", 30},
        {"Bob", 25},
        {"Charlie", 35}
    };

    auto it = std::ranges::find(people, "Bob", &Person::name);

    // 生成数字的views::iota
    for (int i : std::views::iota(1, 6)) {
        std::cout << i << " ";  // 1 2 3 4 5
    }
    std::cout << "
";

    // 拆分视图
    std::string text = "one,two,three";
    for (auto word : text | std::views::split(',')) {
        for (char c : word) {
            std::cout << c;
        }
        std::cout << " ";
    }
}

最佳实践

  1. 对复杂类型和迭代器使用auto,但简单类型保持明确
  2. 优先使用lambdas而非函数对象进行内联操作和回调
  3. 使用范围for循环代替手动迭代器操作
  4. {}初始化变量以防止窄化转换
  5. 为资源拥有类实现移动构造函数和赋值
  6. 在所有权转移时使用std::move,而非一般优化
  7. 优先使用结构化绑定而非std::get<>()处理元组和对
  8. 使用概念约束模板并改进错误消息
  9. 利用范围进行序列的可组合惰性操作
  10. 对大对象使用const auto&进行范围for循环

常见陷阱

  1. 过度使用auto,在类型提供清晰性时降低代码可读性
  2. 在lambda中捕获引用但其捕获对象寿命超出范围
  3. 对const对象使用std::move,禁用移动语义
  4. 忘记在移动操作上使用noexcept,阻止优化
  5. 在范围for循环中修改容器
  6. 结构化绑定临时对象导致的悬垂引用
  7. 使用折叠表达式而不考虑运算符优先级
  8. 假设范围视图创建副本而非提供惰性视图
  9. 从后续将再次使用的对象移动
  10. 未将移动构造函数和赋值标记为noexcept

何时使用现代C++特性

当需要时使用现代C++特性:

  • 更简洁、更具表达性的代码,减少样板
  • 更好的类型安全,通过概念和结构化绑定
  • 通过移动语义提高性能
  • 使用lambdas和范围的功能式编程模式
  • 更少模板复杂度的泛型编程
  • 通过智能指针更安全的资源管理
  • 更易维护和重构的代码
  • 通过概念获得更好的编译器错误消息
  • 通过范围进行惰性求值和组合
  • 从较旧的C++代码库迁移到现代标准

资源