第四章:高级特性
📚 章节概述
本章深入探讨现代C++的高级特性,包括Lambda表达式、函数包装器、移动语义、变参模板、可选类型等。这些特性让C++变得更加强大和表达力丰富,是掌握现代C++编程的关键内容。
🎯 学习目标
学完本章后,您将能够:
- 熟练使用Lambda表达式的各种捕获方式
- 掌握
std::function和函数包装器的使用 - 深入理解移动语义和完美转发
- 掌握变参模板的设计和实现
- 使用
std::optional和std::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++代码更加现代、高效和表达力强。

3776

被折叠的 条评论
为什么被折叠?



