大纲 C++ 11 的 function 类模板 概念介绍 function
是 C++ 11 引入的一个类模板,用于存储任何可以调用的目标(如普通函数、函数指针、函数对象、Lambda 表达式等),并通过统一的接口进行调用。它能够封装和管理函数,允许将函数作为对象传递和存储,位于 <functional>
头文件中,常用于回调和高阶函数。
使用说明
用函数类型实例化 function
类模板 通过 function
类模板调用 operator()
函数的时候,需要根据函数类型传入相应的参数 使用特点
通过类型擦除技术存储任意可调用对象(普通函数、Lambda 表达式、仿函数、成员函数指针等),无需关心具体类型,仅需关注调用签名 编译时会检查参数和返回类型是否匹配,避免了传统函数指针的类型不安全问题 使用场景
事件回调 作为函数参数传递可调用对象 存储 Lambda 表达式 对比说明 C 语言中的函数指针与 C++ 的 function
类模板的对比如下:
特性 函数指针 (C 语言) function
类模板 (C++) 灵活性 只能指向具有匹配签名的函数 可以封装多种类型的可调用对象 (函数、Lambda、函数对象) 状态管理 不支持状态封装 支持状态封装(如 Lambda 表达式和函数对象) 类型安全 不提供额外的类型安全 提供类型安全检查 性能开销 较低 可能有较高的内存和性能开销 多态性 不支持多态 支持多态
C 语言中的函数指针与 C++ 的 function
类模板的区别如下:
基本概念
函数指针(C 语言)函数指针是一个变量,用于存储函数的地址。通过该指针,可以间接调用对应的函数。 C 语言中的函数指针需要显式指定函数签名(返回值类型和参数类型)。 function
类模板(C++):function
是 C++ 11 引入的类模板,提供了一种通用的、类型安全的方式来存储、传递和调用可调用对象(如普通函数、函数指针、Lambda 表达式、函数对象等)。它可以封装多种不同类型的可调用对象,并且允许它们通过统一的接口被调用。 灵活性和类型支持
函数指针(C 语言): 函数指针只能指向具有相同函数签名(参数类型和返回类型)的函数。 不支持封装函数对象、Lambda 表达式等其他类型的可调用对象。 function
类模板(C++):function
支持多种类型的可调用对象,包括普通函数、函数指针、Lambda 表达式、函数对象等。它的模板参数可以适配任意函数签名,支持更加灵活的调用。 还支持捕获外部状态的 Lambda 表达式,或者包含状态的函数对象。 状态管理
函数指针(C 语言): 函数指针无法封装额外的状态信息,指向的仅仅是一个函数。 如果需要管理状态(如在函数调用前后执行某些操作),必须依赖外部的代码来实现。 function
类模板(C++):function
可以封装状态信息。例如,Lambda 表达式和函数对象可以拥有成员变量和成员函数,允许在调用时使用封装的状态。这种能力使得 function
在处理回调和事件处理时更具优势。 类型安全
函数指针(C 语言): 函数指针本身类型是静态的,编译时要求函数签名必须匹配,但它不提供额外的类型安全检查,错误的使用可能导致未定义行为。 function
类模板(C++):function
是类型安全的,编译时会检查存储的可调用对象是否与声明的函数签名一致。C++ 编译器提供了类型安全的保证,避免了函数签名不匹配带来的错误。 内存管理和性能
函数指针(C 语言): 函数指针直接存储函数的地址,不涉及额外的内存分配,因此它的性能开销较小。 由于没有额外的封装,也没有多态或状态的管理,性能上较为高效。 function
类模板(C++):function
需要进行额外的内存分配和类型擦除(Type Erasure)。对于 Lambda 表达式和函数对象,它会封装一个通用的接口,这可能带来额外的性能开销。但是,它的灵活性和类型安全是 function
的优势。 多态和扩展性
函数指针(C 语言): 函数指针没有多态性。它们只是简单地指向某个函数,无法支持运行时多态。 function
类模板(C++):function
支持通过函数对象、Lambda 表达式和虚拟函数等方式实现运行时多态,提供了更大的灵活性。它可以封装复杂的行为,例如结合面向对象编程中的继承和多态来实现不同的回调机制。 使用案例 案例代码一 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <iostream> #include <functional> #include <string> using namespace std;void hello1 () { cout << "hello world" << endl; } void hello2 (string str) { cout << "hello " << str << endl; } int sum (int a, int b) { return a + b; } int main () { function<void ()> function1 = hello1; function1 (); function<void (string)> function2 = hello2; function2 ("peter" ); function<int (int , int )> function3 = sum; int total = function3 (1 , 2 ); cout << "total = " << total << endl; function<int (int , int )> function4 = [](int a, int b) {return a + b; }; int total2 = function4 (3 , 5 ); cout << "total2 = " << total2 << endl; return 0 ; }
程序运行输出的结果如下:
1 2 3 4 hello world hello peter total = 3 total2 = 8
案例代码二 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <iostream> #include <functional> #include <limits> #include <map> using namespace std;class Test {public : void hello (string str) { cout << "hello " << str << endl; } }; int main () { Test t; function<void (Test*, string)> function1 = &Test::hello; function1 (&t, "peter" ); function1 (&Test (), "peter" ); return 0 ; }
程序运行输出的结果如下:
案例代码三 使用 function
函数对象类型来实现图书管理系统的菜单列表选择功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 #include <iostream> #include <functional> #include <string> #include <map> using namespace std;void doShowAllBooks () { cout << "查看所有书籍" << endl; }; void doBorrowBook () { cout << "借书" << endl; }; void doBackBook () { cout << "还书" << endl; } void doQueryBook () { cout << "查询书籍" << endl; } void doLoginOut () { cout << "注销" << endl; } int main () { int choice = 0 ; map<int , function<void ()>> actionMap; actionMap.insert ({ 1 , doShowAllBooks }); actionMap.insert ({ 2 , doBorrowBook }); actionMap.insert ({ 3 , doBackBook }); actionMap.insert ({ 4 , doQueryBook }); actionMap.insert ({ 5 , doLoginOut }); for (;;) { cout << "\n-------------------" << endl; cout << "1. 查看所有书籍" << endl; cout << "2. 借书" << endl; cout << "3. 还书" << endl; cout << "4. 查询书籍" << endl; cout << "5. 注销" << endl; cout << "-------------------" << endl; cout << "请选择: " ; if (!(cin >> choice)) { cout << "输入数字无效,请重新输入!" << endl; cin.clear (); cin.ignore (numeric_limits<streamsize>::max (), '\n' ); continue ; } auto it = actionMap.find (choice); if (it == actionMap.end ()) { cout << "输入数字无效,请重新输入!" << endl; continue ; } it->second (); } return 0 ; }
底层原理 案例代码一 模拟实现 function
类模板的功能,并调用拥有一个参数且不带返回值的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #include <iostream> #include <functional> #include <string> using namespace std;template <typename Fty>class myfunction {}; template <typename R, typename ARG>class myfunction <R (ARG)> {public : using PFUNC = R (*)(ARG); myfunction (PFUNC pfunc) : _pfunc(pfunc) { } R operator () (ARG arg) { return _pfunc(arg); } private : PFUNC _pfunc; }; void hello (string str) { cout << "hello " << str << endl; } int main () { myfunction<void (string)> func1 = hello; func1 ("peter" ); return 0 ; }
程序运行输出的结果如下:
案例代码二 模拟实现 function
类模板的功能,并调用拥有两个参数且带返回值的函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 #include <iostream> #include <functional> #include <string> using namespace std;template <typename Fty>class myfunction {}; template <typename R, typename ARG1, typename ARG2>class myfunction <R (ARG1, ARG2)> {public : using PFUNC = R (*)(ARG1, ARG2); myfunction (PFUNC pfunc) : _pfunc(pfunc) { } R operator () (ARG1 arg1, ARG2 arg2) { return _pfunc(arg1, arg2); } private : PFUNC _pfunc; }; int sum (int a, int b) { return a + b; } int main () { myfunction<int (int , int )> func1 = sum; int result = func1 (3 , 5 ); cout << "result: " << result << endl; return 0 ; }
程序运行输出的结果如下:
案例代码三 模拟实现 function
类模板的功能,并调用拥有不同数量参数(可变参数列表)的函数,避免编写多个模板类的特例化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 #include <iostream> #include <functional> #include <string> using namespace std;template <typename Fty>class myfunction {}; template <typename R, typename ... ARG>class myfunction <R (ARG...)> {public : using PFUNC = R (*)(ARG...); myfunction (PFUNC pfunc) : _pfunc(pfunc) { } R operator () (ARG... arg) { return _pfunc(arg...); } private : PFUNC _pfunc; }; void hello (string str) { cout << "hello " << str << endl; } int sum (int a, int b) { return a + b; } int main () { myfunction<void (string)> func1 = hello; func1 ("peter" ); myfunction<int (int , int )> func2 = sum; int result = func2 (3 , 4 ); cout << "result: " << result << endl; return 0 ; }
程序运行输出的结果如下:
C++ 11 的 bind 绑定器 概念介绍 bind 的概念 bind
是 C++ 标准库 <functional>
头文件中的一个工具,用于创建可调用对象(Callable Object),它可以将函数与部分参数进行绑定,并返回一个新的可调用对象,方便后续调用。
主要作用
固定部分参数:可以预先绑定部分参数,简化后续调用的接口。 调整参数顺序:可以自定义参数的传递顺序,使函数调用更加灵活。 与标准库配合:可以与 function
、thread
、STL 算法等一起使用,提高程序的灵活性。 关键点
bind
返回一个可调用对象(函数对象),类似于 Lambda 表达式。placeholders::_1, placeholders::_2, ...
代表占位符(最多可以有 20 个),表示绑定器调用时需要提供的参数。适用于普通函数、类成员函数、仿函数(函数对象)等。 使用场景
配合 function
类模板使用,用于回调管理。 与 thread
配合,用于传递类成员函数。 在 STL 算法中自定义比较或筛选规则。 提示
尽管 bind
功能强大,但在 C++ 11 之后,Lambda 表达式在大多数情况下更加直观,建议优先使用 Lambda 表达式。
bind1st 与 bind2nd 的概念 bind1st
和 bind2nd
是 C++ 标准库 <functional>
头文件中的函数适配器,用于对二元(两个参数)函数对象进行绑定,使其成为一元(单参数)函数对象。这两个函数适配器用于旧版 C++(C++ 98 / C++ 03),在 C++ 11 及更新版本中已被 bind
取代。
bind1st
:绑定二元(两个参数)函数对象的第一个参数,生成一个新的一元函数对象,该函数对象接收原函数的第二个参数作为输入。bind2nd
:绑定二元(两个参数)函数对象的第二个参数,生成一个新的一元函数对象,该函数对象接收原函数的第一个参数作为输入。使用案例 bind
与 function
基础使用这里主要演示如何使用 C++ 11 中的 bind
和 function
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #include <iostream> #include <functional> using namespace std;void hello (string str) { cout << str << endl; } int sum (int a, int b) { return a + b; } class Test {public : int sum (int a, int b) { return a + b; } }; int main () { bind (hello, "Hello Bind!" )(); int result1 = bind (sum, 3 , 5 )(); cout << result1 << endl; int result2 = bind (&Test::sum, Test (), 5 , 9 )(); cout << result2 << endl; bind (hello, placeholders::_1)("Hello Rust!" ); function<void (string)> func1 = bind (hello, placeholders::_1); func1 ("Hello Python" ); func1 ("Hello Golang" ); function<int (int )> func2 = bind (sum, 6 , placeholders::_1); int result3 = func2 (5 ); cout << result3 << endl; return 0 ; }
程序运行输出的结果如下:
1 2 3 4 5 6 7 Hello Bind! 8 14 Hello Rust! Hello Python Hello Golang 11
bind
与 function
实现线程池这里简单使用 C++ 11 的 bind
和 function
来模拟实现线程池。特别注意,下述代码中的 ThreadPool::startPool()
会调用 join()
来阻塞等待所有子线程执行完成,即线程池运行一次后就会结束,不能重复使用,而且也没有使用到任务队列来优化线程池。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 #include <iostream> #include <functional> #include <vector> #include <thread> using namespace std;class Thread {public : Thread (function<void (int )> func, int id) : _func(func), _id(id) { } thread start () { thread t (_func, _id) ; return t; } private : function<void (int )> _func; int _id; }; class ThreadPool {public : ThreadPool () { } ~ThreadPool () { for (int i = 0 ; i < _pool.size (); i++) { delete _pool[i]; } } void startPool (int size) { for (int i = 0 ; i < size; i++) { _pool.push_back (new Thread (bind (&ThreadPool::runInThread, this , placeholders::_1), i)); } for (int i = 0 ; i < size; i++) { _handler.push_back (_pool[i]->start ()); } for (thread &t : _handler) { t.join (); } } private : vector<Thread *> _pool; vector<thread> _handler; void runInThread (int id) { cout << "call runInThread! id: " << id << endl; } }; int main () { ThreadPool pool; pool.startPool (10 ); return 0 ; }
程序运行输出的结果如下:
1 2 3 4 5 6 7 8 9 10 call runInThread! id: 0 call runInThread! id: 2 call runInThread! id: 5 call runInThread! id: 9 call runInThread! id: 6 call runInThread! id: 8 call runInThread! id: 1 call runInThread! id: 7 call runInThread! id: 4 call runInThread! id: 3
bind1st
与 bind2nd
基础使用这里主要演示如何使用旧版 C++ 提供的 bind1st
与 bind2nd
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 #include <iostream> #include <functional> #include <algorithm> #include <vector> #include <ctime> using namespace std;template <typename Container>void showContainer (Container &con) { typename Container::iterator it = con.begin (); for (; it != con.end (); it++) { cout << *it << " " ; } cout << endl; } void test01 () { vector<int > vec; for (int i = 0 ; i < 10 ; i++) { vec.push_back (rand () % 100 + 1 ); } showContainer (vec); sort (vec.begin (), vec.end ()); showContainer (vec); sort (vec.begin (), vec.end (), greater<int >()); showContainer (vec); } void test02 () { vector<int > vec; for (int i = 0 ; i < 10 ; i++) { vec.push_back (rand () % 100 + 1 ); } showContainer (vec); sort (vec.begin (), vec.end (), greater<int >()); showContainer (vec); vector<int >::iterator it = find_if (vec.begin (), vec.end (), bind1st (greater<int >(), 70 )); if (it != vec.end ()) { cout << "找到小于 70 的第一个元素:" << *it << endl; } else { cout << "未找到符合条件的元素" << endl; } } int main () { srand (time (nullptr )); test01 (); cout << "================================" << endl; test02 (); return 0 ; }
程序运行输出的结果如下:
1 2 3 4 5 6 7 20 67 35 49 100 43 28 63 71 46 20 28 35 43 46 49 63 67 71 100 100 71 67 63 49 46 43 35 28 20 ================================ 76 88 70 53 82 84 42 38 91 64 91 88 84 82 76 70 64 53 42 38 找到小于 70 的第一个元素:64
在 C++ 11 及更新版本中,bind1st
和 bind2nd
已被 bind
取代,示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <iostream> #include <functional> #include <algorithm> #include <vector> using namespace std;int main () { vector<int > vec = {5 , 2 , 4 , 1 , 6 }; function<bool (int )> predicate = bind (greater<int >(), 3 , placeholders::_1); vector<int >::iterator it = find_if (vec.begin (), vec.end (), predicate); if (it != vec.end ()) { cout << "找到小于 3 的第一个元素:" << *it << endl; } else { cout << "未找到符合条件的元素" << endl; } return 0 ; }
程序运行输出的结果如下:
在 C++ 11 及更新版本中,可以使用 Lambda 表达式(更现代的 C++ 方式)来实现,示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <iostream> #include <vector> #include <algorithm> using namespace std;int main () { vector<int > vec = {5 , 2 , 4 , 1 , 6 }; auto it = find_if (vec.begin (), vec.end (), [](int x) { return x < 3 ; }); if (it != vec.end ()) { cout << "找到小于 3 的第一个元素:" << *it << endl; } else { cout << "未找到符合条件的元素" << endl; } return 0 ; }
程序运行输出的结果如下:
bind1st
与 bind2nd
底层原理模拟实现 bind1st 的功能 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 #include <iostream> #include <vector> #include <algorithm> using namespace std;template <typename Compare, typename T>class _my_bind1st {public : _my_bind1st(Compare comp, const T &first) : _comp(comp), _first(first) { } bool operator () (const T &second) { return _comp(_first, second); } private : Compare _comp; T _first; }; template <typename Compare, typename T>_my_bind1st<Compare, T> my_bind1st (Compare comp, const T &first) { return _my_bind1st<Compare, T>(comp, first); } template <typename Iterator, typename Compare>Iterator my_find_if (Iterator first, Iterator last, Compare comp) { for (; first != last; ++first) { if (comp (*first)) { return first; } } return last; } int main () { vector<int > vec = {9 , 6 , 2 , 4 , 1 }; vector<int >::iterator it = my_find_if (vec.begin (), vec.end (), my_bind1st (greater<int >(), 5 )); if (it != vec.end ()) { cout << "找到小于 5 的第一个元素:" << *it << endl; } else { cout << "未找到符合条件的元素" << endl; } return 0 ; }
程序运行输出的结果如下:
模拟实现 bind2nd 的功能 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 #include <iostream> #include <vector> #include <algorithm> using namespace std;template <typename Compare, typename T>class _my_bind2nd {public : _my_bind2nd(Compare comp, const T &second) : _comp(comp), _second(second) { } bool operator () (const T &first) { return _comp(first, _second); } private : Compare _comp; T _second; }; template <typename Compare, typename T>_my_bind2nd<Compare, T> my_bind2nd (Compare comp, const T &second) { return _my_bind2nd<Compare, T>(comp, second); } template <typename Iterator, typename Compare>Iterator my_find_if (Iterator first, Iterator last, Compare comp) { for (; first != last; ++first) { if (comp (*first)) { return first; } } return last; } int main () { vector<int > vec = {9 , 6 , 2 , 4 , 1 }; vector<int >::iterator it = my_find_if (vec.begin (), vec.end (), my_bind2nd (less<int >(), 5 )); if (it != vec.end ()) { cout << "找到小于 5 的第一个元素:" << *it << endl; } else { cout << "未找到符合条件的元素" << endl; } return 0 ; }
程序运行输出的结果如下:
C++ 11 的 Lambda 表达式 概念介绍 C++ 11 的 Lambda 表达式(Lambda Expressions)是一种用于定义匿名函数对象的简洁语法,使得代码更加简洁、灵活。其强大的变量捕获、类型推导和灵活性,使其在现代 C++ 开发中被广泛使用。
Lambda 表达式的语法
[capture](parameter_list) -> return_type {function_body}
,即 [捕获外部变量](形参列表) -> 返回类型 {操作代码}
capture
(捕获列表):定义 Lambda 访问外部变量的方式(比如:按值或按引用)。[]
:表示不捕获任何外部变量[this]
:表示捕获外部的 this
指针。[=]
:表示以传值的方式捕获外部的所有变量。[&]
:表示以传引用的方式捕获外部的所有变量。[=, &a]
:表示以传值的方式捕获外部的所有变量,但是 a
变量以传引用的方式捕获。[a, b]
:表示以传值的方式捕获外部的 a
和 b
变量。[a, &b]
:表示以传值的方式捕获外部的 a
变量,以传引用的方式捕获外部的 b
变量。parameter_list
(形参列表):类似普通函数的参数。return_type
(返回类型):可省略,通常编译器可自动推导。function_body
(函数体):Lambda 实现的具体逻辑。Lambda 表达式的适用场景
STL 算法的回调(如 std::for_each
) 多线程编程(如 std::thread
) 回调函数(如事件处理) 临时函数对象(避免定义冗长的 struct
) Lambda 表达式的本质
C++ Lambda 表达式的本质是匿名的函数对象(Functor),即 没有名字的类的实例。C++ 编译器在编译 Lambda 时,会自动生成一个匿名类,并在其中重载 operator () 函数,从而使其行为类似于函数。值得一提的是,C++ Lambda 不是单纯的 “匿名函数”,而是一个匿名类的实例,即匿名的函数对象。
使用案例 Lambda 的核心特性 1 2 3 4 int x = 10 , y = 20 ;auto lambda1 = [x, &y]() -> void { y = x + y; }; lambda1 ();cout << y;
1 2 auto add = [](int a, int b) -> int { return a + b; };cout << add (3 , 5 );
1 2 3 4 int a = 5 ;auto modify = [a]() mutable -> int { a *= 2 ; return a; };cout << modify () << endl; cout << a << endl;
1 2 3 4 #include <functional> function<int (int , int )> func = [](int a, int b) -> int { return a + b; }; cout << func (2 , 3 );
1 2 3 4 5 #include <vector> #include <algorithm> vector<int > v = {1 , 2 , 3 , 4 , 5 }; for_each(v.begin (), v.end (), [](int item) -> void { cout << item * 2 << " " ; });
提示
若希望在 Lambda 表达式中不指定返回类型,那么可以省略 -> return_type
,比如:auto add = [](int a, int b) { return a + b; };
Lambda 的基础使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> #include <vector> #include <algorithm> #include <ctime> using namespace std;int main () { srand (time (nullptr )); vector<int > vec; for (int i = 0 ; i < 10 ; ++i) { vec.push_back (rand () % 100 + 1 ); } for_each(vec.begin (), vec.end (), [](int item) -> void { cout << item << " " ; }); cout << endl; sort (vec.begin (), vec.end (), [](int a, int b) -> bool { return a > b; }); for_each(vec.begin (), vec.end (), [](int item) -> void { cout << item << " " ; }); cout << endl; auto it = find_if (vec.begin (), vec.end (), [](int item) -> bool { return item < 50 ; }); if (it != vec.end ()) { cout << "找到小于 50 的第一个元素:" << *it << endl; } else { cout << "未找到符合条件的元素" << endl; } return 0 ; }
程序运行输出的结果如下:
1 2 3 91 18 37 28 55 86 50 47 66 52 91 86 66 55 52 50 47 37 28 18 找到小于 50 的第一个元素:47
Lambda 的应用实践 这里主要介绍 Lambda 表达式的各种应用实战场景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 #include <iostream> #include <memory> #include <map> #include <queue> #include <functional> using namespace std;class Data {public : Data (int a, int b) : _a(a), _b(b) { } int getA () { return _a; } int getB () { return _b; } private : int _a; int _b; }; void test01 () { map<int , function<int (int , int )>> map; map[0 ] = [](int a, int b) -> int { return a + b; }; map[1 ] = [](int a, int b) -> int { return a - b; }; map[2 ] = [](int a, int b) -> int { return a * b; }; map[3 ] = [](int a, int b) -> int { return a / b; }; cout << "30 + 15 = " << map[0 ](30 , 15 ) << endl; cout << "30 - 15 = " << map[1 ](30 , 15 ) << endl; cout << "30 * 15 = " << map[2 ](30 , 15 ) << endl; cout << "30 / 15 = " << map[3 ](30 , 15 ) << endl; } void test02 () { unique_ptr<FILE, function<void (FILE *)>> ptr1 (fopen ("data.txt" , "w" ), [](FILE *p) -> void { fclose (p); cout << "Closed File" << endl; }); } void test03 () { using FUNC = function<bool (Data &, Data &)>; priority_queue<Data, vector<Data>, FUNC> queue ([](Data &data1, Data &data2) { return data1.getA () < data2.getA (); }); queue.push (Data (10 , 20 )); queue.push (Data (18 , 25 )); queue.push (Data (15 , 23 )); queue.push (Data (19 , 28 )); while (!queue.empty ()) { Data data = queue.top (); queue.pop (); cout << "a = " << data.getA () << ", b = " << data.getB () << endl; } } int main () { test01 (); cout << "----------------" << endl; test02 (); cout << "----------------" << endl; test03 (); cout << "----------------" << endl; return 0 ; }
程序运行输出的结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 30 + 15 = 45 30 - 15 = 15 30 * 15 = 450 30 / 15 = 2 ---------------- Closed File ---------------- a = 19, b = 28 a = 18, b = 25 a = 15, b = 23 a = 10, b = 20 ----------------
Lambda 的底层原理 C++ Lambda 表达式的本质是匿名的函数对象(Functor),即 没有名字的类的实例。C++ 编译器在编译 Lambda 时,会自动生成一个匿名类,并在其中重载 operator()
函数,从而使其行为类似于函数。值得一提的是,C++ Lambda 不是单纯的 “匿名函数”,而是一个匿名类的实例,即匿名的函数对象。
Lambda 是一个匿名类的实例
编译器会为 Lambda 生成一个 匿名类,该类重载了 operator()
以实现调用操作。 这个匿名类的实例(匿名函数对象)即 Lambda 本身。 Lambda 具有函数对象的性质
Lambda 可以像普通函数一样被调用。 如果 Lambda 捕获了外部变量(如 auto func = [x](int y) -> int { return x + y; };
),那么编译器会为该匿名类生成成员变量来存储 x
,并在 operator()
函数中使用这些成员变量。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 #include <iostream> using namespace std;template <typename T=void >class MyLambda1 { public : MyLambda1 () { } T operator ()() { cout << "Hello World" << endl; } }; void test01 () { auto func1 = []() -> void { cout << "Hello World" << endl; }; func1 (); MyLambda1<> t1; t1 (); } template <typename T>class MyLambda2 {public : MyLambda2 () { } T operator () (int a, int b) const { return a + b; } }; void test02 () { auto fun2 = [](int a, int b) -> int { return a + b; }; cout << fun2 (3 , 5 ) << endl; MyLambda2<int > t2; cout << t2 (3 , 5 ) << endl; } template <typename T=void >class MyLambda3 { public : MyLambda3 (int a, int b) : _a(a), _b(b) { } void operator ()() const { int temp = _a; _a = _b; _b = temp; } private : mutable int _a; mutable int _b; }; void test03 () { int a = 10 ; int b = 30 ; auto func3 = [a, b]() mutable -> void { int temp = a; a = b; b = temp; }; func3 (); cout << "a = " << a << ", b = " << b << endl; MyLambda3<int > t3 (a, b) ; t3 (); cout << "a = " << a << ", b = " << b << endl; } template <typename T=void >class MyLambda4 { public : MyLambda4 (int &a, int &b) : _a(a), _b(b) { } void operator ()() const { int temp = _a; _a = _b; _b = temp; } private : int &_a; int &_b; }; void test04 () { int a = 10 ; int b = 30 ; auto func4 = [&a, &b]() mutable -> void { int temp = a; a = b; b = temp; }; func4 (); cout << "a = " << a << ", b = " << b << endl; MyLambda4<int > t4 (a, b) ; t4 (); cout << "a = " << a << ", b = " << b << endl; } int main () { test01 (); cout << "----------------" << endl; test02 (); cout << "----------------" << endl; test03 (); cout << "----------------" << endl; test04 (); cout << "----------------" << endl; return 0 ; }
程序运行输出的结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 Hello World Hello World ---------------- 8 8 ---------------- a = 10, b = 30 a = 10, b = 30 ---------------- a = 30, b = 10 a = 10, b = 30 ----------------
验证 Lambda 表达式是函数对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <iostream> using namespace std;int main () { auto lambda = [](int x) { return x * 2 ; }; cout << std::boolalpha; cout << "Lambda 是对象吗? " << boolalpha << is_object<decltype (lambda)>::value << '\n' ; cout << "Lambda(5) = " << lambda (5 ) << '\n' ; return 0 ; }
程序运行输出的结果如下:
1 2 Lambda 是对象吗? true Lambda(5) = 10