🔥 C++11 新特性完全指南

概述

C++11 是现代 C++ 开发的里程碑,带来了众多实用特性,让代码更简洁、更高效、更易读。本文详细介绍三大核心特性:auto 类型推导、范围 for 循环和 lambda 表达式。


💡 一、auto 类型推导

基本概念

auto 关键字让编译器自动推断变量类型,告别冗长的类型声明,显著提升代码可读性和开发效率。

基础用法示例

// 基本类型推导
auto i = 42;                    // int
auto d = 3.14;                  // double
auto f = 3.14f;                 // float
auto c = 'a';                   // char
auto s = "Hello";               // const char*
auto str = std::string("World"); // std::string

容器类型推导

// STL 容器
auto vec = std::vector<int>{1, 2, 3};           // std::vector<int>
auto lst = std::list<double>{1.1, 2.2, 3.3};    // std::list<double>
auto mp = std::map<std::string, int>{{"a", 1}}; // std::map<std::string, int>
auto st = std::set<int>{1, 2, 3};               // std::set<int>

// 迭代器类型推导
std::vector<int> nums = {1, 2, 3, 4, 5};
auto it = nums.begin();  // std::vector<int>::iterator
auto cit = nums.cbegin(); // std::vector<int>::const_iterator

函数返回值推导

// 配合 decltype 推导返回类型
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
    return t + u;
}

// C++14 起可省略尾置返回类型
template<typename T, typename U>
auto multiply(T t, U u) {
    return t * u;
}

复杂类型推导

// 指针和引用
auto p = new int(10);           // int*
auto& ref = i;                  // int&
const auto ci = 100;            // const int
const auto& cref = i;           // const int&

// 数组推导
int arr[] = {1, 2, 3, 4, 5};
auto arr2 = arr;                // int*(数组退化为指针)
auto& arr3 = arr;               // int (&)[5](保持数组类型)

注意事项

// 陷阱:auto 会忽略顶层 const
const int x = 10;
auto y = x;                     // int(const 被忽略)
const auto z = x;               // const int(显式保留)

// 陷阱:auto 推导初始化列表
auto init_list = {1, 2, 3};     // std::initializer_list<int>
auto single = {42};             // std::initializer_list<int>(不是 int)
auto direct{42};                // int(C++11 起支持)

🌀 二、范围 for 循环

基本概念

范围 for 循环(Range-based for loop)提供了一种简洁的方式来遍历容器,无需编写复杂的迭代器代码。

基础用法示例

// 遍历 vector
std::vector<int> nums = {1, 2, 3, 4, 5};
for (auto n : nums) {
    std::cout << n << " ";
}
// 输出: 1 2 3 4 5

// 使用引用避免拷贝
for (auto& n : nums) {
    n *= 2;  // 修改原容器中的元素
}
// nums 变为: {2, 4, 6, 8, 10}

// 使用 const 引用(只读访问)
for (const auto& n : nums) {
    std::cout << n << " ";  // 不修改,避免拷贝开销
}

遍历各种容器

// 遍历数组
int arr[] = {10, 20, 30, 40, 50};
for (auto& elem : arr) {
    elem += 5;
}

// 遍历 list
std::list<std::string> names = {"Alice", "Bob", "Charlie"};
for (const auto& name : names) {
    std::cout << name << std::endl;
}

// 遍历 map
std::map<int, std::string> students = {
    {1, "张三"},
    {2, "李四"},
    {3, "王五"}
};
for (const auto& pair : students) {
    std::cout << "ID: " << pair.first << ", Name: " << pair.second << std::endl;
}

// 使用结构化绑定(C++17)
for (const auto& [id, name] : students) {
    std::cout << "ID: " << id << ", Name: " << name << std::endl;
}

// 遍历 set
std::set<double> scores = {85.5, 92.0, 78.5, 95.5};
for (auto score : scores) {
    std::cout << score << " ";
}

遍历字符串

// 遍历 std::string
std::string text = "Hello, C++11!";
for (auto& ch : text) {
    ch = std::toupper(ch);  // 转为大写
}

// 遍历 C 风格字符串
const char* cstr = "C++11";
for (auto ch : std::string(cstr)) {
    std::cout << ch << " ";
}

遍历初始化列表

// 直接遍历初始化列表
for (auto x : {1, 2, 3, 4, 5}) {
    std::cout << x * x << " ";
}
// 输出: 1 4 9 16 25

与算法结合

// 配合算法使用
std::vector<int> data = {3, 1, 4, 1, 5, 9, 2, 6};

// 查找满足条件的元素
for (const auto& val : data) {
    if (val > 5) {
        std::cout << "Found: " << val << std::endl;
        break;
    }
}

// 统计满足条件的元素个数
int count = 0;
for (const auto& val : data) {
    if (val % 2 == 0) {
        ++count;
    }
}

🎯 三、Lambda 表达式

基本概念

Lambda 表达式是匿名函数,可以在代码中就地定义,支持灵活捕获外部变量,是函数式编程的重要工具。

语法结构

[capture](parameters) -> return_type { body }
// capture: 捕获列表
// parameters: 参数列表
// return_type: 返回类型(可省略,由编译器推导)
// body: 函数体

基础用法示例

// 最简单的 lambda
auto sayHello = []() { std::cout << "Hello, Lambda!" << std::endl; };
sayHello();

// 带参数的 lambda
auto add = [](int a, int b) { return a + b; };
std::cout << add(3, 5);  // 输出: 8

// 显式指定返回类型
auto divide = [](double a, double b) -> double {
    if (b == 0) return 0;
    return a / b;
};

捕获方式详解

int x = 10;
int y = 20;

// 值捕获(拷贝)
auto lambda1 = [x, y]() { return x + y; };

// 引用捕获
auto lambda2 = [&x, &y]() { x++; y++; };

// 隐式值捕获(所有变量按值)
auto lambda3 = [=]() { return x + y; };

// 隐式引用捕获(所有变量按引用)
auto lambda4 = [&]() { x++; y++; };

// 混合捕获
auto lambda5 = [=, &x]() { x++; return x + y; };  // x 按引用,其他按值
auto lambda6 = [&, y]() { x++; return x + y; };   // y 按值,其他按引用

// 广义捕获(C++14)
auto lambda7 = [z = x + y]() { return z; };  // 捕获表达式的结果

与 STL 算法结合

std::vector<int> nums = {5, 2, 8, 1, 9, 3};

// 排序(降序)
std::sort(nums.begin(), nums.end(), 
          [](int a, int b) { return a > b; });
// nums: {9, 8, 5, 3, 2, 1}

// 查找第一个大于 5 的元素
auto it = std::find_if(nums.begin(), nums.end(),
                       [](int n) { return n > 5; });

// 转换元素
std::vector<int> squares;
std::transform(nums.begin(), nums.end(), std::back_inserter(squares),
               [](int n) { return n * n; });

// 过滤元素
std::vector<int> evens;
std::copy_if(nums.begin(), nums.end(), std::back_inserter(evens),
             [](int n) { return n % 2 == 0; });

// 累加(带初始值)
int sum = std::accumulate(nums.begin(), nums.end(), 0,
                          [](int acc, int n) { return acc + n; });

// 计数
int count = std::count_if(nums.begin(), nums.end(),
                          [](int n) { return n > 5; });

// 删除满足条件的元素
nums.erase(std::remove_if(nums.begin(), nums.end(),
                          [](int n) { return n < 5; }), 
           nums.end());

自定义比较器

// 自定义排序
std::vector<std::pair<std::string, int>> students = {
    {"Alice", 85},
    {"Bob", 92},
    {"Charlie", 78}
};

// 按分数降序排序
std::sort(students.begin(), students.end(),
          [](const auto& a, const auto& b) {
              return a.second > b.second;
          });

// 按名字长度排序
std::sort(students.begin(), students.end(),
          [](const auto& a, const auto& b) {
              return a.first.length() < b.first.length();
          });

递归 Lambda

// C++14 起支持 auto 参数,实现递归
std::function<int(int)> factorial = [&](int n) -> int {
    return n <= 1 ? 1 : n * factorial(n - 1);
};

// 使用 Y 组合子实现递归(C++14)
auto make_factorial = [](auto f) {
    return [f](auto x) -> decltype(x) {
        return f(f, x);
    };
};

auto factorial_impl = [](auto f, int n) -> int {
    return n <= 1 ? 1 : n * f(f, n - 1);
};

auto factorial = make_factorial(factorial_impl);
std::cout << factorial(5);  // 输出: 120

作为回调函数

// 线程回调
std::thread t([]() {
    std::cout << "Running in thread" << std::endl;
});
t.join();

// 异步任务
auto future = std::async(std::launch::async, [](int x) {
    return x * x;
}, 10);
std::cout << future.get();  // 输出: 100

// 定时器回调
std::function<void()> timerCallback = [&]() {
    std::cout << "Timer fired!" << std::endl;
};

闭包应用

// 工厂函数
auto makeMultiplier(int factor) {
    return [factor](int x) { return x * factor; };
}

auto double_it = makeMultiplier(2);
auto triple_it = makeMultiplier(3);

std::cout << double_it(5);  // 输出: 10
std::cout << triple_it(5);  // 输出: 15

// 计数器
auto makeCounter() {
    int count = 0;
    return [count]() mutable { return ++count; };
}

auto counter = makeCounter();
std::cout << counter();  // 输出: 1
std::cout << counter();  // 输出: 2
std::cout << counter();  // 输出: 3

泛型 Lambda(C++14)

// 自动推导参数类型
auto print = [](const auto& x) {
    std::cout << x << std::endl;
};

print(42);           // int
print(3.14);         // double
print("Hello");      // const char*
print(std::string("World"));  // std::string

// 泛型算法
auto isGreaterThan = [](const auto& threshold) {
    return [threshold](const auto& value) {
        return value > threshold;
    };
};

auto greaterThan5 = isGreaterThan(5);
std::cout << greaterThan5(10);  // true
std::cout << greaterThan5(3);   // false

🌟 总结

特性 主要优势 适用场景
auto 简化类型声明,提高代码可读性 复杂类型、模板代码、迭代器
范围 for 简化容器遍历,避免迭代器错误 遍历容器、数组、字符串
Lambda 就地定义函数,灵活捕获变量 算法回调、闭包、异步编程

最佳实践

  1. auto 使用建议

    • 优先使用 auto 简化复杂类型声明
    • 注意顶层 const 的处理
    • 初始化列表的推导要小心
  2. 范围 for 使用建议

    • 使用 const auto& 进行只读遍历
    • 使用 auto& 进行原地修改
    • 避免在循环中修改容器大小
  3. Lambda 使用建议

    • 优先使用值捕获,避免悬空引用
    • 明确指定返回类型提高可读性
    • 利用 mutable 实现有状态的 lambda

C++11 让现代 C++ 开发更优雅、更高效!每天学一点,技术不掉队~


标签: #C++新特性 #编程技巧 #技术分享 #C++学习 #程序员日常

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐