现代C++——高级特性

第四章:高级特性

📚 章节概述

本章深入探讨现代C++的高级特性,包括Lambda表达式、函数包装器、移动语义、变参模板、可选类型等。这些特性让C++变得更加强大和表达力丰富,是掌握现代C++编程的关键内容。

🎯 学习目标

学完本章后,您将能够:

  • 熟练使用Lambda表达式的各种捕获方式
  • 掌握std::function和函数包装器的使用
  • 深入理解移动语义和完美转发
  • 掌握变参模板的设计和实现
  • 使用std::optionalstd::variant处理可选值
  • 理解模板元编程的基础概念
  • 掌握异步编程的基本技巧

1. Lambda表达式详解

📖 理论讲解

Lambda表达式是C++11引入的匿名函数特性,它提供了一种简洁的方式来定义小型函数对象,特别适合与STL算法配合使用。

💡 基本语法

// Lambda表达式的完整语法
[capture list](parameter list) -> return type { function body }

// 简化形式
[capture](parameters) { body }
[capture] { body }  // 无参数时可省略()
[]() { body }       // 无捕获时的形式

🔍 捕获方式详解

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

void demo_lambda_captures() {
    int x = 10, y = 20;
    std::string message = "Hello";
    
    // 1. 按值捕获
    auto lambda1 = [x, y](int z) {
        return x + y + z;  // x和y是拷贝的值
    };
    
    // 2. 按引用捕获
    auto lambda2 = [&x, &y](int delta) {
        x += delta;  // 可以修改原始变量
        y += delta;
        return x + y;
    };
    
    // 3. 混合捕获
    auto lambda3 = [x, &y, message](int value) {
        // x按值捕获,y按引用捕获,message按值捕获
        y += value;  // 可以修改y
        return message + ": " + std::to_string(x + y);
    };
    
    // 4. 捕获所有(按值)
    auto lambda4 = [=](int multiplier) {
        return (x + y) * multiplier;
    };
    
    // 5. 捕获所有(按引用)
    auto lambda5 = [&](int value) {
        x = y = value;
        message = "Modified";
    };
    
    // 6. 混合捕获所有
    auto lambda6 = [=, &y](int value) {
        // 除了y按引用捕获,其他都按值捕获
        y = value;
        return x + y;
    };
    
    std::cout << "Lambda1 result: " << lambda1(5) << std::endl;
    std::cout << "Lambda2 result: " << lambda2(3) << std::endl;
    std::cout << "Lambda3 result: " << lambda3(7) << std::endl;
}

🚀 高级Lambda特性

// 1. mutable Lambda
void demo_mutable_lambda() {
    int x = 10;
    
    auto lambda = [x](int delta) mutable {
        x += delta;  // mutable允许修改按值捕获的变量
        return x;
    };
    
    std::cout << "Lambda result: " << lambda(5) << std::endl;  // 15
    std::cout << "Original x: " << x << std::endl;             // 10(未改变)
}

// 2. 泛型Lambda(C++14)
void demo_generic_lambda() {
    auto generic_lambda = [](auto a, auto b) {
        return a + b;
    };
    
    std::cout << generic_lambda(1, 2) << std::endl;           // 3
    std::cout << generic_lambda(1.5, 2.5) << std::endl;      // 4.0
    std::cout << generic_lambda(std::string("Hello"), 
                               std::string(" World")) << std::endl; // Hello World
}

// 3. 初始化捕获(C++14)
void demo_init_capture() {
    auto lambda = [counter = 0](int increment) mutable {
        counter += increment;
        return counter;
    };
    
    std::cout << lambda(1) << std::endl;  // 1
    std::cout << lambda(2) << std::endl;  // 3
    std::cout << lambda(3) << std::endl;  // 6
}

// 4. 完美转发Lambda
template<typename F, typename... Args>
auto make_perfect_lambda(F&& f, Args&&... args) {
    return [f = std::forward<F>(f), args...](auto&&... inner_args) {
        return f(args..., std::forward<decltype(inner_args)>(inner_args)...);
    };
}

🎯 Lambda与STL算法

void demo_lambda_with_stl() {
    std::vector<int> numbers = {5, 2, 8, 1, 9, 3, 7, 4, 6};
    
    // 1. 查找偶数
    auto even_it = std::find_if(numbers.begin(), numbers.end(),
                                [](int n) { return n % 2 == 0; });
    
    // 2. 计算偶数个数
    int even_count = std::count_if(numbers.begin(), numbers.end(),
                                  [](int n) { return n % 2 == 0; });
    
    // 3. 转换操作
    std::vector<int> squares;
    std::transform(numbers.begin(), numbers.end(), std::back_inserter(squares),
                  [](int n) { return n * n; });
    
    // 4. 自定义排序
    std::vector<std::string> words = {"apple", "date", "banana", "cherry"};
    std::sort(words.begin(), words.end(),
             [](const std::string& a, const std::string& b) {
                 return a.length() < b.length();  // 按长度排序
             });
    
    // 5. 累积操作
    int sum = std::accumulate(numbers.begin(), numbers.end(), 0,
                             [](int acc, int n) { return acc + n; });
    
    // 6. 分区操作
    std::partition(numbers.begin(), numbers.end(),
                  [](int n) { return n % 2 == 1; });  // 奇数在前
}

2. std::function - 函数包装器

📖 理论讲解

std::function是一个多态的函数包装器,可以存储、复制和调用任何可调用对象(函数、Lambda、函数对象等)。

💡 基本用法

#include <functional>

// 1. 包装普通函数
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }

std::function<int(int, int)> operation = add;
std::cout << operation(3, 4) << std::endl;  // 7

operation = multiply;
std::cout << operation(3, 4) << std::endl;  // 12

// 2. 包装Lambda表达式
std::function<int(int, int)> lambda_op = [](int a, int b) { return a - b; };
std::cout << lambda_op(10, 3) << std::endl;  // 7

// 3. 包装函数对象
struct Divider {
    int operator()(int a, int b) const { return a / b; }
};

std::function<int(int, int)> functor_op = Divider{};
std::cout << functor_op(15, 3) << std::endl;  // 5

🚀 高级应用

// 1. 回调函数系统
class EventHandler {
private:
    std::vector<std::function<void(int)>> callbacks_;
    
public:
    void register_callback(std::function<void(int)> callback) {
        callbacks_.push_back(std::move(callback));
    }
    
    void trigger_event(int value) {
        for (const auto& callback : callbacks_) {
            callback(value);
        }
    }
};

void demo_callback_system() {
    EventHandler handler;
    
    // 注册不同类型的回调
    handler.register_callback([](int val) {
        std::cout << "Lambda callback: " << val << std::endl;
    });
    
    handler.register_callback([](int val) {
        std::cout << "Square: " << val * val << std::endl;
    });
    
    handler.trigger_event(5);
}

// 2. 策略模式
class Calculator {
private:
    std::function<double(double, double)> strategy_;
    
public:
    void set_strategy(std::function<double(double, double)> strategy) {
        strategy_ = std::move(strategy);
    }
    
    double calculate(double a, double b) {
        return strategy_ ? strategy_(a, b) : 0.0;
    }
};

void demo_strategy_pattern() {
    Calculator calc;
    
    calc.set_strategy([](double a, double b) { return a + b; });
    std::cout << "Addition: " << calc.calculate(10, 5) << std::endl;
    
    calc.set_strategy([](double a, double b) { return a * b; });
    std::cout << "Multiplication: " << calc.calculate(10, 5) << std::endl;
}

// 3. 条件处理链
template<typename T>
class ProcessorChain {
private:
    std::vector<std::function<void(T&)>> processors_;
    
public:
    void add_processor(std::function<void(T&)> processor) {
        processors_.push_back(std::move(processor));
    }
    
    void process(T& data) {
        for (const auto& processor : processors_) {
            processor(data);
        }
    }
};

3. 移动语义和完美转发

📖 理论讲解

移动语义是现代C++的核心特性之一,它通过转移资源而非拷贝资源来提高性能。完美转发则确保参数以原始的值类别传递给其他函数。

💡 移动语义基础

class MoveableResource {
private:
    std::unique_ptr<int[]> data_;
    size_t size_;
    std::string name_;
    
public:
    // 构造函数
    MoveableResource(const std::string& name, size_t size) 
        : name_(name), size_(size), data_(std::make_unique<int[]>(size)) {
        std::cout << "Resource '" << name_ << "' constructed" << std::endl;
    }
    
    // 拷贝构造函数
    MoveableResource(const MoveableResource& other) 
        : name_(other.name_ + "_copy"), size_(other.size_), 
          data_(std::make_unique<int[]>(other.size_)) {
        std::copy(other.data_.get(), other.data_.get() + size_, data_.get());
        std::cout << "Resource '" << name_ << "' copy constructed" << std::endl;
    }
    
    // 移动构造函数
    MoveableResource(MoveableResource&& other) noexcept
        : name_(std::move(other.name_)), size_(other.size_), 
          data_(std::move(other.data_)) {
        other.size_ = 0;
        std::cout << "Resource '" << name_ << "' move constructed" << std::endl;
    }
    
    // 拷贝赋值运算符
    MoveableResource& operator=(const MoveableResource& other) {
        if (this != &other) {
            name_ = other.name_ + "_assigned";
            size_ = other.size_;
            data_ = std::make_unique<int[]>(other.size_);
            std::copy(other.data_.get(), other.data_.get() + size_, data_.get());
            std::cout << "Resource '" << name_ << "' copy assigned" << std::endl;
        }
        return *this;
    }
    
    // 移动赋值运算符
    MoveableResource& operator=(MoveableResource&& other) noexcept {
        if (this != &other) {
            name_ = std::move(other.name_);
            size_ = other.size_;
            data_ = std::move(other.data_);
            other.size_ = 0;
            std::cout << "Resource '" << name_ << "' move assigned" << std::endl;
        }
        return *this;
    }
    
    size_t size() const { return size_; }
    const std::string& name() const { return name_; }
};

void demo_move_semantics() {
    MoveableResource resource1("Resource1", 100);
    
    // 拷贝
    MoveableResource resource2 = resource1;
    
    // 移动
    MoveableResource resource3 = std::move(resource1);
    
    std::cout << "After move, resource1 size: " << resource1.size() << std::endl;
    std::cout << "Resource3 size: " << resource3.size() << std::endl;
}

🚀 完美转发

#include <utility>

// 完美转发函数模板
template<typename T, typename... Args>
std::unique_ptr<T> make_object(Args&&... args) {
    return std::make_unique<T>(std::forward<Args>(args)...);
}

// 完美转发到函数调用
template<typename F, typename... Args>
auto call_function(F&& f, Args&&... args) -> decltype(f(std::forward<Args>(args)...)) {
    std::cout << "Calling function with perfect forwarding" << std::endl;
    return f(std::forward<Args>(args)...);
}

void demo_perfect_forwarding() {
    // 创建对象的完美转发
    auto resource = make_object<MoveableResource>("TempResource", 50);
    
    // 函数调用的完美转发
    auto lambda = [](const std::string& s, int n) {
        return s + std::to_string(n);
    };
    
    std::string temp = "hello";
    auto result1 = call_function(lambda, temp, 42);          // 左值
    auto result2 = call_function(lambda, "world", 123);      // 右值
    
    std::cout << "Result1: " << result1 << std::endl;
    std::cout << "Result2: " << result2 << std::endl;
}

// 转发构造函数示例
template<typename T>
class Wrapper {
private:
    T data_;
    
public:
    template<typename... Args>
    Wrapper(Args&&... args) : data_(std::forward<Args>(args)...) {
        std::cout << "Wrapper constructed with forwarding" << std::endl;
    }
    
    T& get() { return data_; }
    const T& get() const { return data_; }
};

4. 变参模板 (Variadic Templates)

📖 理论讲解

变参模板允许模板接受可变数量的参数,是实现泛型编程的强大工具。

💡 基础语法

// 1. 基本变参模板
template<typename... Args>
void print_values(Args... args) {
    // C++17折叠表达式
    ((std::cout << args << " "), ...);
    std::cout << std::endl;
}

// 2. 递归展开(C++17之前的方式)
template<typename T>
void print_recursive(T&& t) {
    std::cout << t << std::endl;
}

template<typename T, typename... Args>
void print_recursive(T&& t, Args&&... args) {
    std::cout << t << " ";
    print_recursive(args...);
}

// 3. 参数包大小
template<typename... Args>
void print_count(Args... args) {
    std::cout << "Argument count: " << sizeof...(args) << std::endl;
    std::cout << "Type count: " << sizeof...(Args) << std::endl;
}

🚀 高级应用

// 1. 安全的printf实现
template<typename... Args>
void safe_printf(const std::string& format, Args... args) {
    std::cout << "Safe printf with " << sizeof...(args) << " arguments: ";
    // 简化的实现,实际应该解析格式字符串
    ((std::cout << args << " "), ...);
    std::cout << std::endl;
}

// 2. 元组操作
template<typename... Args>
auto make_tuple_sum(Args... args) {
    return (args + ...);  // C++17折叠表达式
}

// 3. 类型安全的容器初始化
template<typename Container, typename... Args>
Container make_container(Args&&... args) {
    Container container;
    (container.push_back(std::forward<Args>(args)), ...);
    return container;
}

void demo_variadic_templates() {
    print_values(1, 2.5, "hello", 'c', true);
    print_count(1, "two", 3.0);
    
    safe_printf("Values: %d %s %f", 42, "world", 3.14159);
    
    auto sum = make_tuple_sum(1, 2, 3, 4, 5);
    std::cout << "Sum: " << sum << std::endl;
    
    auto vec = make_container<std::vector<int>>(1, 2, 3, 4, 5);
    std::cout << "Vector size: " << vec.size() << std::endl;
}

// 4. 编译时条件处理
template<typename T, typename... Args>
constexpr bool all_same_type() {
    return (std::is_same_v<T, Args> && ...);
}

template<typename... Args>
void process_if_all_integers(Args... args) {
    if constexpr (all_same_type<int, Args...>()) {
        std::cout << "All arguments are integers: ";
        ((std::cout << args << " "), ...);
        std::cout << std::endl;
    } else {
        std::cout << "Not all arguments are integers" << std::endl;
    }
}

5. std::optional - 可选值类型

📖 理论讲解

std::optional是C++17引入的类型,用于表示可能存在也可能不存在的值,提供了类型安全的空值表示。

💡 基本用法

#include <optional>

// 1. 创建optional
std::optional<int> divide_safe(int a, int b) {
    if (b != 0) {
        return a / b;
    }
    return std::nullopt;  // 表示无值
}

void demo_optional_basic() {
    auto result1 = divide_safe(10, 2);
    auto result2 = divide_safe(10, 0);
    
    // 检查是否有值
    if (result1) {
        std::cout << "10 / 2 = " << *result1 << std::endl;
    }
    
    if (result2.has_value()) {
        std::cout << "10 / 0 = " << result2.value() << std::endl;
    } else {
        std::cout << "Division by zero - no result" << std::endl;
    }
    
    // 提供默认值
    int safe_result = result2.value_or(-1);
    std::cout << "Result with default: " << safe_result << std::endl;
}

🚀 高级应用

// 1. 链式操作
std::optional<std::string> get_user_name(int user_id) {
    if (user_id > 0 && user_id < 100) {
        return "User" + std::to_string(user_id);
    }
    return std::nullopt;
}

std::optional<int> get_name_length(const std::string& name) {
    if (!name.empty()) {
        return static_cast<int>(name.length());
    }
    return std::nullopt;
}

void demo_optional_chaining() {
    auto name = get_user_name(42);
    if (name) {
        auto length = get_name_length(*name);
        if (length) {
            std::cout << "Name length: " << *length << std::endl;
        }
    }
    
    // 更简洁的写法(需要手动实现或使用第三方库)
    auto result = get_user_name(42)
        .and_then([](const std::string& n) { return get_name_length(n); });
}

// 2. 配置类中的可选字段
struct Config {
    std::string host = "localhost";
    std::optional<int> port;
    std::optional<std::string> username;
    std::optional<std::string> password;
    
    void print() const {
        std::cout << "Host: " << host << std::endl;
        std::cout << "Port: " << port.value_or(8080) << std::endl;
        
        if (username) {
            std::cout << "Username: " << *username << std::endl;
        }
        
        if (password) {
            std::cout << "Password: [HIDDEN]" << std::endl;
        }
    }
};

// 3. 缓存系统
template<typename Key, typename Value>
class SimpleCache {
private:
    std::unordered_map<Key, Value> cache_;
    
public:
    void put(const Key& key, const Value& value) {
        cache_[key] = value;
    }
    
    std::optional<Value> get(const Key& key) const {
        auto it = cache_.find(key);
        if (it != cache_.end()) {
            return it->second;
        }
        return std::nullopt;
    }
    
    Value get_or_compute(const Key& key, std::function<Value()> compute) {
        if (auto cached = get(key)) {
            return *cached;
        }
        
        Value value = compute();
        put(key, value);
        return value;
    }
};

6. std::variant - 变体类型

📖 理论讲解

std::variant是C++17引入的类型安全的联合体,可以在编译时安全地存储多种类型中的一种。

💡 基本用法

#include <variant>

void demo_variant_basic() {
    // 1. 创建variant
    std::variant<int, double, std::string> value;
    
    value = 42;
    std::cout << "Holds int: " << std::get<int>(value) << std::endl;
    
    value = 3.14159;
    std::cout << "Holds double: " << std::get<double>(value) << std::endl;
    
    value = "Hello Variant!";
    std::cout << "Holds string: " << std::get<std::string>(value) << std::endl;
    
    // 2. 检查当前类型
    std::cout << "Current type index: " << value.index() << std::endl;
    
    // 3. 类型检查
    if (std::holds_alternative<std::string>(value)) {
        std::cout << "Currently holds a string" << std::endl;
    }
    
    // 4. 安全访问
    if (auto* str_ptr = std::get_if<std::string>(&value)) {
        std::cout << "String value: " << *str_ptr << std::endl;
    }
}

🚀 访问者模式

// 1. 使用std::visit
struct Visitor {
    void operator()(int i) const {
        std::cout << "Integer: " << 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;
    }
};

void demo_variant_visitor() {
    std::variant<int, double, std::string> values[] = {
        42, 3.14159, std::string("Hello")
    };
    
    for (const auto& value : values) {
        std::visit(Visitor{}, value);
    }
    
    // 使用Lambda访问者
    for (const auto& value : values) {
        std::visit([](const auto& v) {
            using T = std::decay_t<decltype(v)>;
            if constexpr (std::is_same_v<T, int>) {
                std::cout << "Lambda: Integer " << v << std::endl;
            } else if constexpr (std::is_same_v<T, double>) {
                std::cout << "Lambda: Double " << v << std::endl;
            } else if constexpr (std::is_same_v<T, std::string>) {
                std::cout << "Lambda: String " << v << std::endl;
            }
        }, value);
    }
}

// 2. 计算访问者
struct CalculatorVisitor {
    template<typename T, typename U>
    auto operator()(const T& a, const U& b) const {
        if constexpr (std::is_arithmetic_v<T> && std::is_arithmetic_v<U>) {
            return a + b;
        } else {
            return std::string("Cannot add these types");
        }
    }
};

void demo_variant_calculator() {
    std::variant<int, double, std::string> a = 10;
    std::variant<int, double, std::string> b = 3.14;
    std::variant<int, double, std::string> c = "hello";
    
    auto result1 = std::visit(CalculatorVisitor{}, a, b);
    auto result2 = std::visit(CalculatorVisitor{}, a, c);
    
    std::cout << "10 + 3.14 = " << result1 << std::endl;
    std::cout << "10 + hello = " << result2 << std::endl;
}

🎯 实际应用场景

// 1. 表达式求值器
struct Number { double value; };
struct BinaryOp { 
    char op; 
    std::unique_ptr<Expression> left, right; 
};

using Expression = std::variant<Number, BinaryOp>;

// 2. 状态机
enum class ConnectionState { Disconnected, Connecting, Connected, Error };

struct StateData {
    std::variant<
        std::monostate,           // Disconnected
        std::string,              // Connecting (server address)
        int,                      // Connected (connection id)
        std::string               // Error (error message)
    > data;
    
    ConnectionState state;
};

// 3. 配置值
using ConfigValue = std::variant<bool, int, double, std::string>;

class Configuration {
private:
    std::unordered_map<std::string, ConfigValue> config_;
    
public:
    template<typename T>
    void set(const std::string& key, const T& value) {
        config_[key] = value;
    }
    
    template<typename T>
    std::optional<T> get(const std::string& key) const {
        auto it = config_.find(key);
        if (it != config_.end()) {
            if (auto* value = std::get_if<T>(&it->second)) {
                return *value;
            }
        }
        return std::nullopt;
    }
};

🧪 实践练习

练习1:事件系统设计

// 使用variant设计一个类型安全的事件系统
enum class EventType { Mouse, Keyboard, Network };

struct MouseEvent { int x, y; bool pressed; };
struct KeyboardEvent { char key; bool pressed; };
struct NetworkEvent { std::string message; };

using Event = std::variant<MouseEvent, KeyboardEvent, NetworkEvent>;

class EventHandler {
public:
    void handle_event(const Event& event);
    // 实现事件分发逻辑
};

练习2:表达式解析器

// 使用variant和visitor模式实现简单的数学表达式解析器
struct Number { double value; };
struct Variable { std::string name; };
struct BinaryOperation { 
    char op; 
    std::unique_ptr<Expression> left, right; 
};

using Expression = std::variant<Number, Variable, BinaryOperation>;

class ExpressionEvaluator {
public:
    double evaluate(const Expression& expr, 
                   const std::unordered_map<std::string, double>& variables);
};

练习3:异步任务管理器

// 使用std::optional和std::function实现异步任务管理
template<typename T>
class TaskManager {
public:
    using Task = std::function<T()>;
    using Callback = std::function<void(std::optional<T>)>;
    
    void submit_task(Task task, Callback callback);
    void process_tasks();
    
private:
    // 实现任务队列和执行逻辑
};

📝 本章小结

本章介绍的高级特性是现代C++编程的核心工具:

🎯 核心概念回顾

  • Lambda表达式:提供了简洁的匿名函数语法,特别适合与STL算法配合使用
  • std::function:类型擦除的函数包装器,实现回调和策略模式的利器
  • 移动语义:通过转移资源避免拷贝,显著提升性能
  • 变参模板:实现真正的泛型编程,类型安全的可变参数
  • std::optional:类型安全的可选值,消除空指针异常
  • std::variant:类型安全的联合体,实现和类型的完美工具

🚀 设计模式应用

这些特性让许多设计模式的实现变得更加简洁和类型安全:

  • 策略模式(std::function)
  • 访问者模式(std::variant + std::visit)
  • 观察者模式(Lambda + std::function)
  • 工厂模式(变参模板 + 完美转发)

🎯 性能优化

  • 使用移动语义减少不必要的拷贝
  • Lambda的就地定义避免函数调用开销
  • variant的零开销抽象
  • optional的栈分配避免动态内存

掌握这些高级特性,将让您的C++代码更加现代、高效和表达力强。


🔗 相关资源

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值