C++11特性(二)

目录

  • [3. 可变参数模板](#3. 可变参数模板)
    • [3.1 基本语法](#3.1 基本语法)
    • [3.2 包扩展](#3.2 包扩展)
    • [3.3 完美转发](#3.3 完美转发)
    • [3.4 emplace系列接口](#3.4 emplace系列接口)
  • [4 lambda](#4 lambda)
    • [4.1 lambda表达式语法](#4.1 lambda表达式语法)
    • [4.2 捕捉列表](#4.2 捕捉列表)
    • [4.3 lambda的应用](#4.3 lambda的应用)
  • [5. 包装器](#5. 包装器)
    • [5.1 基本概念](#5.1 基本概念)
    • [5.2 function的应用](#5.2 function的应用)
    • [5.3 bind](#5.3 bind)
      • [5.3.1 基本语法](#5.3.1 基本语法)
      • [5.3.2 占位符](#5.3.2 占位符)
      • [5.3.3 bind的使用](#5.3.3 bind的使用)
  • 总结

3. 可变参数模板

3.1 基本语法

C++11支持可变参数模板,也就是说支持可变数量参数的函数模板和类模板,可变数目的参数被称
为参数包,存在两种参数包:模板参数包,表示零或多个模板参数;函数参数包:表示零或多个函
数参数。

复制代码
template <class ...Args> void Func(Args... args) {} 
template <class ...Args> void Func(Args&... args) {}
template <class ...Args> void Func(Args&&... args) {}

可变参数模板的原理跟模板类似,本质还是去实例化对应类型和个数的多个函数。

可变参数模板在编译期展开,所有操作都发生在编译阶段。

这一点至关重要。参数包不是数组,不能像数组那样在运行时通过下标 args[i] 去访问。所有的"遍历"和"处理"都必须借助编译期的技术手段来完成:
示例:

复制代码
template <class ...Args>
void Print(Args... args)
{
	 // 不支持
	 // 可变参数模板编译时解析
	 // 下面是运行获取和解析,所以不支持这样用
	/* for (size_t i = 0; i < sizeof...(args); i++)
	 {
		cout << args[i] << " ";
	 }*/
	cout << sizeof...(args) << endl;
	 cout << endl;
}
int main()
{
double x = 2.2;
//Print(); // 包里有0个参数
Print(1); // 包里有1个参数
Print(1, string("xxxxx")); // 包里有2个参数
Print(1.1, string("xxxxx"), x); // 包里有3个参数
return 0;
}

3.2 包扩展

对于一个参数包,我们除了能计算它的参数个数,我们能做的唯一的事情就是扩展它 。当扩展一个包时,我们还要提供用于每个扩展元素的模式 。扩展一个包就是将它分解为构成的元素,对每个元素应用模式,获得扩展后的列表。我们通过在模式的右边放一个省略号(...)来触发扩展操作。底层的实现细节如图1所示。

C++还支持更复杂的包扩展,直接将参数包依次展开依次作为实参给一个函数去处理。

复制代码
void ShowList()
{
	cout << endl;
}
template <class T, class ...Args>
void ShowList(T x, Args... args)
{
cout << x << " ";
ShowList(args...);
}
template <class ...Args>
void Print(Args... args)
{
// N个参数,第一个传给x,剩下N-1参数传给ShowList的第二个参数包
ShowList(args...);
}
//void ShowList(double x)
//{
//	cout << x << " ";
//	ShowList();
//}
//
//void ShowList(string x, double x3)
//{
//	cout << x << " ";
//	ShowList(x3);
//}
//
//void ShowList(int x, string x2, double x3)
//{
//	cout << x << " ";
//	ShowList(x2, x3);
//}
//
//void Print(int x1, string x2, double x3)
//{
//	ShowList(x1, x2, x3);
//}
int main()
{
double x = 2.2;
Print(1, string("xxxxx"), x); // 包里有3个参数
return 0;
}

调用链展开过程:

复制代码
┌─────────────────────────────────────────────────────────────────┐
│ 第1步:main 调用 Print(1, "xxxxx", 2.2)                       │
│   → Print 的参数包 args = {1, "xxxxx", 2.2}                   │
│   → Print 调用 ShowList(args...)                              │
│   → ShowList(1, "xxxxx", 2.2) 被实例化                       │
│                                                                 │
│ 第2步:ShowList(1, "xxxxx", 2.2)                              │
│   → T = int, x = 1                                           │
│   → Args = {string, double}, args = {"xxxxx", 2.2}           │
│   → 打印: 1                                                   │
│   → 调用 ShowList(args...) → ShowList("xxxxx", 2.2)          │
│                                                                 │
│ 第3步:ShowList("xxxxx", 2.2)                                 │
│   → T = string, x = "xxxxx"                                  │
│   → Args = {double}, args = {2.2}                            │
│   → 打印: xxxxx                                               │
│   → 调用 ShowList(args...) → ShowList(2.2)                   │
│                                                                 │
│ 第4步:ShowList(2.2)                                          │
│   → T = double, x = 2.2                                      │
│   → Args = {}, args = 空包                                    │
│   → 打印: 2.2                                                 │
│   → 调用 ShowList(args...) → ShowList()                      │
│                                                                 │
│ 第5步:ShowList()                                              │
│   → 打印换行                                                   │
│   → 递归结束                                                   │
└─────────────────────────────────────────────────────────────────┘

3.3 完美转发

完美转发是 C++11 引入的重要特性,它允许一个函数模板将它的参数原封不动地 转发给另一个函数,保持参数的所有性质不变(包括类型、左值/右值属性、const/volatile 修饰等)。

假设我们有一个工厂函数 make_obj,它接收参数并转发给 Object 的构造函数:

复制代码
template <typename T>
void func(T param) {
    // 想要把 param 转发给另一个函数
    other_func(param);   // ❌ 参数的性质可能丢失!
}

问题paramfunc 内部是一个左值 (即使传入的是右值),转发给 other_func 时会丢失右值属性,导致无法调用移动构造函数等,造成性能损失。

要实现完美转发,需要三个要素:

要素 作用
万能引用(Universal Reference) T&& 能接收左值和右值
引用折叠(Reference Collapsing) 处理 T&& 与具体类型的组合
std::forward 保持参数的原始值类别进行转发

std::forward 的作用:

std::forward<T>(arg) 根据模板参数 T 的类型来决定返回左值还是右值:

T 的类型 forward<T>(arg) 返回
T(非引用) 右值
T&(左值引用) 左值
T&&(右值引用) 右值

示例:

复制代码
#include <iostream>
#include <utility>
using namespace std;
// ============ 目标函数 ============
void target(int& x) {
cout << "target(int&): 左值引用, x = " << x << endl;
}
void target(int&& x) {
cout << "target(int&&): 右值引用, x = " << x << endl;
}
void target(const int& x) {
cout << "target(const int&): const 左值引用, x = " << x << endl;
}
// ============ 不完美转发的包装函数 ============
template <typename T>
void bad_wrapper(T arg) {   // 值传递,丢失引用属性
target(arg);   // 永远传递左值
}
// ============ 完美转发的包装函数 ============
template <typename T>
void good_wrapper(T&& arg) {   // 万能引用
target(std::forward<T>(arg));   // 完美转发
}
int main() {
int a = 10;
const int b = 20;
cout &lt;&lt; "===== 直接调用目标函数 =====" &lt;&lt; endl;
target(a);        // int&amp;  → target(int&amp;)
target(30);       // 右值  → target(int&amp;&amp;)
target(b);        // const int&amp; → target(const int&amp;)
cout &lt;&lt; "\n===== 不完美转发(值传递) =====" &lt;&lt; endl;
bad_wrapper(a);   // 传递给 target 的是左值 → target(int&amp;)
bad_wrapper(30);  // 传递给 target 的是左值 → target(int&amp;) ❌ 丢失右值属性
bad_wrapper(b);   // 传递给 target 的是左值 → target(int&amp;) ❌ 丢失 const
cout &lt;&lt; "\n===== 完美转发 =====" &lt;&lt; endl;
good_wrapper(a);   // 保持左值 → target(int&amp;)
good_wrapper(30);  // 保持右值 → target(int&amp;&amp;) ✅
good_wrapper(b);   // 保持 const 左值 → target(const int&amp;) ✅
return 0;
}

输出:

复制代码
===== 直接调用目标函数 =====
target(int&): 左值引用, x = 10
target(int&&): 右值引用, x = 30
target(const int&): const 左值引用, x = 20
===== 不完美转发(值传递) =====
target(int&): 左值引用, x = 10
target(int&): 左值引用, x = 30    ← 右值变左值,丢失了移动语义
target(int&): 左值引用, x = 20    ← 丢失了 const
===== 完美转发 =====
target(int&): 左值引用, x = 10
target(int&&): 右值引用, x = 30   ← 右值被正确保持
target(const int&): const 左值引用, x = 20  ← const 被正确保持

3.4 empalce系列接口

emplace 系列接口是 C++11 引入的特性,主要存在于标准库容器中,用于就地构造元素,避免不必要的拷贝或移动操作,从而提升性能。

复制代码
template <class... Args> void emplace_back (Args&&... args);
template <class... Args> iterator emplace (const_iterator position,
Args&&... args);

3.4.1 vector::emplace_back 简化实现:

复制代码
#include <iostream>
#include <utility>
using namespace std;
class MyVector {
private:
char* data;        // 原始内存
size_t size;       // 当前元素个数
size_t capacity;   // 容量
public:
MyVector() : data(nullptr), size(0), capacity(0) {}
template &lt;class... Args&gt;
void emplace_back(Args&amp;&amp;... args) {
    // 1. 检查是否需要扩容
    if (size &gt;= capacity) {
        capacity = capacity == 0 ? 1 : capacity * 2;
        char* new_data = new char[capacity * sizeof(int)];
    // 将已有对象移动到新内存(简化实现)
    if (data) {
        for (size_t i = 0; i &amp;lt; size; ++i) {
            int* p = (int*)(new_data + i * sizeof(int));
            int* old_p = (int*)(data + i * sizeof(int));
            new (p) int(std::move(*old_p));
        }
        delete[] data;
    }
    data = new_data;
}

// 2. 在尾部位置就地构造对象
int* pos = (int*)(data + size * sizeof(int));
new (pos) int(std::forward&amp;lt;Args&amp;gt;(args)...);
++size;
}
void print() {
for (size_t i = 0; i &lt; size; ++i) {
cout &lt;&lt; (int)(data + i * sizeof(int)) &lt;&lt; " ";
}
cout &lt;&lt; endl;
}
~MyVector() {
// 析构对象(简化版)
delete[] data;
}
};
int main() {
MyVector v;
v.emplace_back(10);   // 直接构造 int
v.emplace_back(20);
v.emplace_back(30);
v.print();   // 输出: 10 20 30
return 0;
}

3.4.2 使用场景对比:

复制代码
vector<Student> v;
v.reserve(3);
Student s1("张三", 20);
// 方式1:push_back - 传入已有对象
v.push_back(s1);              // 拷贝构造一次
v.push_back(std::move(s1));   // 移动构造一次
// 方式2:push_back - 传入临时对象
v.push_back(Student("李四", 21));  // 构造 + 移动
// 方式3:emplace_back - 就地构造
v.emplace_back("王五", 22);   // 只有一次构造,无拷贝/移动
// 方式4:emplace_back - 移动语义
Student s2("赵六", 23);
v.emplace_back(std::move(s2));  // 只有一次移动构造

4 lambda

4.1 lambda表达式语法

lambda 表达式本质是一个匿名函数对象,和普通函数不一样的是,它可以定义在函数内部。 从 lambda 表达式的语法使用层面来讲它没有类型,所以我们通常使用 auto 或者模板参数定义的对象来接收 lambda 对象。

基本语法结构:

复制代码
[capture](parameters) -> return_type { body }
部分 说明 是否必须
[capture] 捕获列表:指定从外部作用域捕获哪些变量 ✅ 必须
(parameters) 参数列表:函数的形参 ❌ 可省略(无参时)
-> return_type 返回类型:指定返回值类型 ❌ 可省略(可推导时)
{ body } 函数体:具体的执行代码 ✅ 必须

示例:

复制代码
#include <iostream>
using namespace std;
int main() {
// 最简单的 lambda:无参数,无捕获,无返回值
[] { cout << "Hello Lambda!" << endl; };
//  ↑  ↑                                ↑
//  捕获  参数                           函数体
// 要执行 lambda,需要调用它
[] { cout &lt;&lt; "Hello Lambda!" &lt;&lt; endl; }();   // 加 () 立即执行
// 或者赋值给变量后调用
auto sayHello = [] { cout &lt;&lt; "Hello Lambda!" &lt;&lt; endl; };
sayHello();   // 调用
return 0;
}

4.2 捕捉列表

C++ lambda 捕获规则复述:

  • lambda 表达式默认仅可以使用 lambda 函数体与参数内的变量;若要使用外层作用域的变量,就需要进行捕获
  1. 显式捕获 在捕获列表里写明变量,分为值捕获引用捕获 ;多个捕获变量之间用逗号隔开。 示例:[x, y, &z]:x、y 为值捕获,z 为引用捕获。
  2. 隐式捕获 不在捕获列表逐个列出变量,交给编译器自动捕获用到的外层变量:
  • [=]:隐式值捕获
  • [&]:隐式引用捕获
  1. 混合捕获(隐式 + 显式一起用)
  • [=, &x]:其余变量全部隐式值捕获,唯独 x 使用引用捕获
  • [&, x, y]:其余变量全部隐式引用捕获,唯独 x、y 使用值捕获

混合捕获强制规则:捕获列表第一个元素必须是&=

  • 开头为&(默认引用捕获),后面显式列出的变量只能是值捕获
  • 开头为=(默认值捕获),后面显式列出的变量只能是引用捕获

示例:

复制代码
int a = 1, b = 2, c = 3;
// ========== 值捕获 ==========
[a] { cout << a << endl; };   // 只捕获 a(值拷贝)
[a, b] { cout << a + b << endl; };   // 捕获 a 和 b(值拷贝)
// ========== 引用捕获 ==========
[&a] { a = 10; };   // 捕获 a(引用),可以修改外部变量
[&a, &b] { a = b; };   // 捕获 a 和 b(引用)
// ========== 隐式捕获 ==========
[=] { cout << a + b + c << endl; };   // 全部值捕获(拷贝)
[&] { a = b + c; };   // 全部引用捕获
// ========== 混合捕获 ==========
[=, &a] { a = b + c; };   // a 引用捕获,其他全部值捕获
[&, a] { cout << a + b << endl; };   // a 值捕获,其他全部引用捕获

4.3 lambda的应用

在接触 lambda 表达式之前,C++ 里可供我们使用的可调用对象只有函数指针仿函数。 函数指针的类型声明书写繁琐;而仿函数则需要专门定义一个类,编写起来同样比较麻烦。 而借助 lambda 表达式来快速创建可调用对象,写法更加简洁高效,使用起来十分方便。

复制代码
struct Goods
{
	string _name; // 名字
	double _price; // 价格
	int _evaluate; // 评价
	// ...
Goods(const char* str, double price, int evaluate)
	:_name(str)
	, _price(price)
	, _evaluate(evaluate)
{}
};
struct ComparePriceLess
{
bool operator()(const Goods& gl, const Goods& gr)
{
return gl._price < gr._price;
}
};
struct ComparePriceGreater
{
bool operator()(const Goods& gl, const Goods& gr)
{
return gl._price > gr._price;
}
};
//
int main()
{
vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3}, { "菠萝", 1.5, 4 } };
// 类似这样的场景,我们实现仿函数对象或者函数指针支持商品中
// 不同项的比较,相对还是比较麻烦的,那么这里lambda就很好用了
//sort(v.begin(), v.end(), ComparePriceLess());
//sort(v.begin(), v.end(), ComparePriceGreater());
sort(v.begin(), v.end(), [](const Goods&amp; g1, const Goods&amp; g2) {
	return g1._price &lt; g2._price;
	});
sort(v.begin(), v.end(), [](const Goods&amp; g1, const Goods&amp; g2) {
return g1._price &gt; g2._price;
});
sort(v.begin(), v.end(), [](const Goods&amp; g1, const Goods&amp; g2) {
return g1._evaluate &lt; g2._evaluate;
});
sort(v.begin(), v.end(), [](const Goods&amp; g1, const Goods&amp; g2) {
return g1._evaluate &gt; g2._evaluate;
});
return 0;
}

5. 包装器

5.1 基本概念

std::function 是一个类模板 ,定义在 <functional> 头文件中。它的实例可以包装存储任何可调用对象,包括:

  • 普通函数

  • 函数指针

  • 仿函数(函数对象)

  • Lambda 表达式

  • std::bind 表达式

  • 类的成员函数(静态/非静态)

    template
    class function; // 未定义
    template <class Ret, class... Args>
    class function<Ret(Args...)>; // 特化版本

核心特征:

特性 说明
类型统一 不同可调用对象可以被统一包装为 std::function 类型
类型安全 编译期检查参数类型和返回值类型
目标存储 存储的可调用对象称为 function 的"目标"
空状态 不含目标时称为"空"
异常安全 调用空的 std::function 会抛出 std::bad_function_call 异常
复制代码
#include <iostream>
#include <functional>
using namespace std;
// ============ 普通函数 ============
int f(int a, int b) {
return a + b;
}
// ============ 仿函数 ============
struct Functor {
public:
int operator()(int a, int b) {
return a + b;
}
};
// ============ 包含成员函数的类 ============
class Plus {
public:
Plus(int n = 10) : _n(n) {}
// 静态成员函数
static int plusi(int a, int b) {
    return a + b;
}
// 普通成员函数(有隐含的 this 指针)
double plusd(double a, double b) {
return (a + b) * _n;
}
private:
int _n;
};
int main() {
// ========== 包装各种可调用对象 ==========
function<int(int, int)> f1 = f;                    // 普通函数
function<int(int, int)> f2 = Functor();            // 仿函数
function<int(int, int)> f3 = [](int a, int b) {    // Lambda
return a + b;
};
cout &lt;&lt; f1(1, 1) &lt;&lt; endl;  // 输出: 2
cout &lt;&lt; f2(1, 1) &lt;&lt; endl;  // 输出: 2
cout &lt;&lt; f3(1, 1) &lt;&lt; endl;  // 输出: 2
// ========== 包装静态成员函数 ==========
// 成员函数要指定类域并且前面加 &amp; 才能获取地址
function&lt;int(int, int)&gt; f4 = &amp;Plus::plusi;
cout &lt;&lt; f4(1, 1) &lt;&lt; endl;  // 输出: 2
// ========== 包装普通成员函数 ==========
// 普通成员函数还有一个隐含的 this 指针参数
// 所以绑定时传对象或者对象的指针都可以
// 方式1:传入对象指针 (Plus*)
function&lt;double(Plus*, double, double)&gt; f5 = &amp;Plus::plusd;
Plus pd;
cout &lt;&lt; f5(&amp;pd, 1.1, 1.1) &lt;&lt; endl;  // 输出: (2.2) * 10 = 22
// 方式2:传入对象本身 (Plus)
function&lt;double(Plus, double, double)&gt; f6 = &amp;Plus::plusd;
cout &lt;&lt; f6(pd, 1.1, 1.1) &lt;&lt; endl;   // 输出: 22
// 方式3:传入右值对象 (Plus&amp;&amp;)
function&lt;double(Plus&amp;&amp;, double, double)&gt; f7 = &amp;Plus::plusd;
cout &lt;&lt; f7(move(pd), 1.1, 1.1) &lt;&lt; endl;  // 输出: 22
cout &lt;&lt; f7(Plus(), 1.1, 1.1) &lt;&lt; endl;    // 输出: (2.2) * 10 = 22
return 0;
}

5.2 function的应用

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*''/'

  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。

  • 两个整数之间的除法总是 向零截断

  • 表达式中不含除零运算。

  • 输入是一个根据逆波兰表示法表示的算术表达式。

  • 答案及所有中间计算结果可以用 32 位 整数表示。

    // 传统⽅式的实现
    class Solution {
    public:
    int evalRPN(vector& tokens) {
    stack st;
    for (auto& str : tokens)
    {
    if (str == "+" || str == "-" || str == "" || str == "/")
    {
    int right = st.top();
    st.pop();
    int left = st.top();
    st.pop();
    switch (str[0])
    {
    case '+':
    st.push(left + right);
    break;
    case '-':
    st.push(left - right);
    break;
    case '
    ':
    st.push(left * right);
    break;
    case '/':
    st.push(left / right);
    break;
    }
    }
    else
    {
    st.push(stoi(str));
    }
    }
    return st.top();
    }
    };
    // 使⽤map映射string和function的⽅式实现
    // 这种⽅式的最⼤优势之⼀是⽅便扩展,假设还有其他运算,我们增加map中的映射即可
    class Solution {
    public:
    int evalRPN(vector& tokens) {
    stack st;
    // function作为map的映射可调⽤对象的类型
    map<string, function<int(int, int)>> opFuncMap = {
    {"+", [](int x, int y) {return x + y; }},
    {"-", [](int x, int y) {return x - y; }},
    {"*", [](int x, int y) {return x * y; }},
    {"/", [](int x, int y) {return x / y; }}
    };
    for (auto& str : tokens)
    {
    if (opFuncMap.count(str)) // 操作符
    {
    int right = st.top();
    st.pop();
    int left = st.top();
    st.pop();
    int ret = opFuncMap[str](left, right);
    st.push(ret);
    }
    else
    {
    st.push(stoi(str));
    }
    }
    return st.top();
    }
    };

5.3 bind

std::bind 是 C++11 引入的函数适配器 ,它可以将一个可调用对象(函数、仿函数、Lambda、成员函数等)的某些参数预先绑定 为固定值,或调整参数顺序,从而生成一个新的可调用对象。

复制代码
// 版本1:自动推导返回类型
template <class Fn, class... Args>
/* unspecified */ bind(Fn&& fn, Args&&... args);
// 版本2:显式指定返回类型
template <class Ret, class Fn, class... Args>
/* unspecified */ bind(Fn&& fn, Args&&... args);
5.3.1 基本语法
复制代码
auto newCallable = bind(callable, arg_list);
  • callable:被包装的可调用对象(函数、仿函数、Lambda、成员函数等)

  • arg_list:逗号分隔的参数列表,对应 callable 的参数

  • newCallable:返回的新的可调用对象

5.3.2 占位符

arg_list 中的参数可能包含形如 _n 的名字(n 是整数),这些参数是占位符,表示新可调用对象的参数位置:

占位符 含义
_1 newCallable 的第一个参数
_2 newCallable 的第二个参数
_n newCallable 的第 n 个参数
5.3.3 bind的使用
复制代码
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
using namespace std;
// 使用占位符
using namespace std::placeholders;
// ==================== 普通函数 ====================
int calculate(int a, int b, int c) {
return (a + b) * c;
}
// ==================== 测试用的类 ====================
class Calculator {
private:
int factor;
public:
Calculator(int f = 10) : factor(f) {}
// 静态成员函数
static int add(int a, int b) {
    return a + b;
}
// 普通成员函数(有隐含的 this 指针)
int multiply(int a, int b) const {
return (a + b) * factor;
}
};
// ==================== main 函数 ====================
int main() {
cout << "========== std::bind 核心特性 ==========\n" << endl;
// ===== 特性1:固定部分参数(最常用) =====
cout &lt;&lt; "【特性1】固定部分参数" &lt;&lt; endl;
cout &lt;&lt; "----------------------------------------" &lt;&lt; endl;
// calculate 需要3个参数:(a+b)*c
// 固定 c = 10,变成只需要2个参数
auto calc_with_c10 = bind(calculate, _1, _2, 10);
cout &lt;&lt; "calc_with_c10(5, 3) = " &lt;&lt; calc_with_c10(5, 3) &lt;&lt; endl;   // (5+3)*10 = 80
// 固定 a = 100,b = 20,变成只需要1个参数
auto calc_fixed_ab = bind(calculate, 100, 20, _1);
cout &lt;&lt; "calc_fixed_ab(5) = " &lt;&lt; calc_fixed_ab(5) &lt;&lt; endl;         // (100+20)*5 = 600
// 固定所有参数,变成无参函数
auto calc_all_fixed = bind(calculate, 5, 3, 2);
cout &lt;&lt; "calc_all_fixed() = " &lt;&lt; calc_all_fixed() &lt;&lt; endl;         // (5+3)*2 = 16
cout &lt;&lt; "\n";
// ===== 特性2:调整参数顺序 =====
cout &lt;&lt; "【特性2】调整参数顺序" &lt;&lt; endl;
cout &lt;&lt; "----------------------------------------" &lt;&lt; endl;
// 正常顺序:a = _1, b = _2
auto sub_normal = bind(minus&lt;int&gt;(), _1, _2);
cout &lt;&lt; "sub_normal(10, 5) = " &lt;&lt; sub_normal(10, 5) &lt;&lt; endl;   // 10-5 = 5
// 交换顺序:a = _2, b = _1
auto sub_swapped = bind(minus&lt;int&gt;(), _2, _1);
cout &lt;&lt; "sub_swapped(10, 5) = " &lt;&lt; sub_swapped(10, 5) &lt;&lt; endl; // 5-10 = -5
cout &lt;&lt; "\n";
// ===== 特性3:绑定成员函数 =====
cout &lt;&lt; "【特性3】绑定成员函数" &lt;&lt; endl;
cout &lt;&lt; "----------------------------------------" &lt;&lt; endl;
Calculator calc(5);
// 3.1 静态成员函数(没有 this,和普通函数一样)
auto static_bind = bind(Calculator::add, _1, _2);
cout &lt;&lt; "static_bind(100, 200) = " &lt;&lt; static_bind(100, 200) &lt;&lt; endl;   // 300
// 3.2 普通成员函数(需要绑定对象)
// 方式1:绑定对象指针
auto member_bind1 = bind(&amp;Calculator::multiply, &amp;calc, _1, _2);
cout &lt;&lt; "member_bind1(3, 4) = " &lt;&lt; member_bind1(3, 4) &lt;&lt; endl;   // (3+4)*5 = 35
// 方式2:绑定对象本身 + 固定参数
auto member_bind2 = bind(&amp;Calculator::multiply, calc, 10, _1);
cout &lt;&lt; "member_bind2(5) = " &lt;&lt; member_bind2(5) &lt;&lt; endl;         // (10+5)*5 = 75
cout &lt;&lt; "\n";
// ===== 特性4:STL 算法中的应用 =====
cout &lt;&lt; "【特性4】STL 算法中的应用" &lt;&lt; endl;
cout &lt;&lt; "----------------------------------------" &lt;&lt; endl;
vector&lt;int&gt; numbers = {10, 25, 30, 45, 50, 65, 70};
// 统计大于 40 的元素个数
int threshold = 40;
auto greater_than = bind(greater&lt;int&gt;(), _1, threshold);
int count = count_if(numbers.begin(), numbers.end(), greater_than);
cout &lt;&lt; "大于 " &lt;&lt; threshold &lt;&lt; " 的元素个数: " &lt;&lt; count &lt;&lt; endl;   // 3 (45,65,70)
// 每个元素乘以 2 再加 5
vector&lt;int&gt; result;
result.resize(numbers.size());
auto transform_func = bind(plus&lt;int&gt;(), bind(multiplies&lt;int&gt;(), _1, 2), 5);
transform(numbers.begin(), numbers.end(), result.begin(), transform_func);
cout &lt;&lt; "原始: ";
for (int x : numbers) cout &lt;&lt; x &lt;&lt; " ";
cout &lt;&lt; "\n变换后(每个*2+5): ";
for (int x : result) cout &lt;&lt; x &lt;&lt; " ";
cout &lt;&lt; endl;
return 0;
}

运行结果:

复制代码
========== std::bind 核心特性 ==========
【特性1】固定部分参数
calc_with_c10(5, 3) = 80
calc_fixed_ab(5) = 600
calc_all_fixed() = 16
【特性2】调整参数顺序
sub_normal(10, 5) = 5
sub_swapped(10, 5) = -5
【特性3】绑定成员函数
static_bind(100, 200) = 300
member_bind1(3, 4) = 35
member_bind2(5) = 75
【特性4】STL 算法中的应用
大于 40 的元素个数: 3
原始: 10 25 30 45 50 65 70
变换后(每个*2+5): 25 55 65 95 105 135 145 

总结

可变参数模板是 C++11 引入的编译期特性,通过参数包接收任意数量和类型的参数,并在编译期展开为多个具体实例。其核心价值在于:一是配合包扩展和递归调用实现类型安全的变长参数处理;二是结合万能引用与 std::forward 实现完美转发,保持参数的左值/右值属性与 const 修饰不变;三是支撑 emplace 系列接口在容器中就地构造元素,避免不必要的拷贝和移动,从而提升性能。

lambda 表达式本质是定义在函数内部的匿名函数对象,通过捕获列表(值捕获、引用捕获、隐式捕获、混合捕获)灵活访问外层作用域变量。相比函数指针和仿函数,lambda 写法更简洁,特别适合作为排序比较器、STL 算法回调、std::function 包装对象等场景,是 C++ 现代编程中创建可调用对象的首选方式。

两者在实际开发中经常配合使用:可变参数模板负责编译期类型安全的参数传递与转发,lambda 负责提供简洁灵活的可调用对象,共同构成 C++11 泛型编程与函数式编程风格的重要基石。

相关推荐
lvwangshu1 小时前
数位 DP 进阶
算法·动态规划
天道kabuto1 小时前
Vue3 升级踩坑:子组件 click 事件为什么会触发两次?
前端
Nayana1 小时前
《Web 到 HarmonyOS》-- Ability、Stage、模块化与路由导航
前端
她的男孩1 小时前
一个开源低代码框架的协作 SPI 是怎么设计的 ForgeAdmin 拆解 + 实战接入新平台
后端·算法·架构
ShineWinsu1 小时前
对于 Vue 3:从为什么学 Vue,到声明式渲染与数据响应式的解析
前端·javascript·vue.js
OPEN-F2 小时前
C++20新特性精讲:概念、范围与三路比较
算法·c++20
tudousisi2222 小时前
CSP 第3题训练 Day 5|CSP202509C HTTP 头信息|Blog A
c++
粥里有勺糖2 小时前
视野修炼-技术周刊第132期 | 一些有趣的组件
前端·github·aigc
এ慕ོ冬℘゜2 小时前
样式控制 .css ()
前端·css