篇一、
一、什么是function包装器 function包装器 也叫作适配器。C++中的function本质是一个类模板,也是一个包装器。
function类模板的原型如下:
template
template
class function
模板参数说明: Ret: 被调用函数的返回类型 Args…:被调用函数的形参
function包装器可以对可调用对象进行包装,包括函数指针(函数名)、仿函数(函数对象)、lambda表达式、类的成员函数。 原文链接:https://blog.csdn.net/weixin_74461263/article/details/143452009
二、为什么要有 包装器function?有什么意义?
2.1 C++中需要包装器function的主要原因:是为了解决不同可调用对象类型不一致的问题,从而减少模板的实例化次数,从而提高代码的通用性和效率。
在C++中,函数指针、仿函数和lambda表达式等都是可调用的类型,但它们在模板中的使用会导致编译时多次实例化,从而影响效率。例如,如果有一个模板函数接收不同类型的可调用对象,编译器会为每种类型的可调用对象生成不同的实例化代码,这会导致大量的重复代码生成,降低效率。为了解决这个问题,C++11引入了std::function包装器,它可以将不同类型的可调用对象统一封装为相同的类型,从而减少模板的实例化次数,提高代码的效率和重用性。
2.2 std::function的基本概念和用法
std::function是一个类模板,定义在头文件
2.3 举例说明:
2.3.1 未使用std::function()包装器之前:
#include "stdafx.h"
#include
#include
using namespace std;
// 函数模板会被实例化多次
template
T useF(F f, T x) //实例化的时候,不会调用useF()函数。只有在调用的时候才会执行useF()函数
{
static int icount = 0;
cout << "count:" << ++icount << endl;
cout << "count:" << &icount << endl;
return f(x);
}
double func(double i)
{
return i / 2;
}
struct Functor
{
double operator()(double d)
{
return d / 3;
}
};
int main()
{
// 函数名
cout << useF(func, 11.11) << endl;
cout << "==========================" << endl;
// 函数对象
cout << useF(Functor(), 11.11) << endl;
cout << "==========================" << endl;
// lamber表达式
cout << useF([](double d)->double { return d / 4; }, 11.11) << endl;
system("pause");
return 0;
}
结果:
在 main 函数中使用了3个不同的函数对象(函数名、函数对象和 lambda 表达式),每个都调用了 useF 函数, 实例化了三份useF函数 (比方说:useF1、useF2、useF3三份函数 ),每个不同的函数对象(函数名、函数对象和 lambda 表达式)调用自己实例化的useF函数。因此count值不会增加,还是1;
由于函数指针、仿函数、lambda表达式是不同的类型,因此useF函数会被实例化出三份,三次调用useF函数所打印count的地址也是不同的。
但实际这里根本没有必要实例化出三份useF函数,因为三次调用useF函数时传入的可调用对象虽然是不同类型的,但这三个可调用对象的返回值和形参类型都是相同的。
这时就可以用包装器分别对着三个可调用对象进行包装,然后再用这三个包装后的可调用对象来调用useF函数,这时就只会实例化出一份useF函数。
2.3.2 使用包装器std::function()代码如下:
int main()
{
// 函数名 生成一个函数包装器,f1就是函数指针 == double (*f1)(double)
std::function
cout << useF(f1, 11.11) << endl;
cout << "==========================" << endl;
// 函数对象
std::function
cout << useF(f2, 11.11) << endl;
cout << "==========================" << endl;
// lamber表达式
std::function
cout << useF(f3, 11.11) << endl;
system("pause");
return 0;
}
结果:
包装后,这三个可调用对象都是相同的function类型,因此最终只会实例化出一份useF函数,该函数的第一个模板参数的类型就是function类型的。
这时三次调用useF函数所打印count的地址就是相同的,并且count在三次调用后会被累加到3,表示这一个useF函数被调用了三次。
2.4 function包装器的意义: 1.将可调用对象的类型进行统一,便于我们对其进行统一化管理。 2.包装后明确了可调用对象的返回值和形参类型,更加方便使用者使用。
三、function包装器的应用
3.1 调用普通函数
#include
#include
int f(int a, int b)
{
return a+b;
}
int main()
{
std::function
cout< system("pause"); return 0; } 3.2 调用函数对象 #include using namespace std; //function object struct functor { public: int operator() (int a, int b) { return a + b; } }; int main() { functor ft; function cout< return 0; } 3.3 调用模板函数对象 #include using namespace std; //function object template struct functor { public: T operator() (T a, T b) { return a + b; } }; int main() { functor ft; function cout< return 0; } 3.4 调用lambda表达式 #include #include using namespace std; int main() { auto f = [](const int a, const int b) {return a + b; }; std::function cout << func(1, 2) << endl; // 3 system("pause"); return 0; } 3.5 调用类静态成员函数 #include #include using namespace std; class Plus { public: static int plus(int a, int b) { return a + b; } }; int main() { function cout << f(1, 2) << endl; //3 system("pause"); return 0; } 3.6 调用类成员函数 #include #include using namespace std; class Plus { public: int plus(int a, int b) { return a + b; } }; int main() { Plus p; function //function cout << f(p,1, 2) << endl; //3 system("pause"); return 0; } 注意:在使用function包装类的成员函数时需要注意,类的非静态成员函数参数中天然包含了一个该类指针参数,即this指针。所以我们包装时需要在function参数列表中,也加上该类指针或者该类,实例化时也同理。 3.7 调用类公有数据成员 #include #include using namespace std; class Plus { Plus(int num_):num(num_){} public: int plus(int a, int b) { return a + b; } int num; }; int main() { const Plus p(2); function //function cout << f(p) << endl; //2 system("pause"); return 0; } 3.8 通过bind函数调用类成员函数 #include #include using namespace std; class Plus { public: int plus(int a, int b) { return a + b; } }; int main() { Plus p; // 指针形式调用成员函数 function // 对象形式调用成员函数 function cout << f(1, 2) << endl; //3 cout << f1(1, 2) << endl; //3 system("pause"); return 0; } 四、function函数在“逆波兰表达式”中的应用: 逆波兰表达式(利用map+function来解决) 分析:我们原本用栈来完成,现在我们可以用map+function来解决改进后,用function把lambda表达式包装起来了lambda相关博客传送门:【C++11特性篇】lambda表达式玩法全解 原文链接:https://blog.csdn.net/qq_35721743/article/details/83217416 原文链接:https://blog.csdn.net/weixin_74461263/article/details/143452009 C++11 【 function包装器,bind包装器】-CSDN博客 篇二、C++11 std::function函数包装器 - kaizenly - 博客园 【1】std::function简介 std::function是一个函数包装器模板,最早来自boost库,对应其boost::function函数包装器。 一个std::function类型对象实例可包装以下可调用元素类型如下: (1)函数 (2)函数指针 (3)类成员函数指针 (4)任意类型的函数对象(例如:定义了operator()操作符重载的类型)。 std::function对象可被拷贝和转移,并且可以使用指定的调用特征来直接调用目标元素。 当std::function对象未包裹任何实际的可调用元素,调用该std::function对象将抛出std::bad_function_call异常。 【2】std::funciton使用 #include #include using namespace std; int subtract(int m, int n) { return (m - n); } template < class T> T g_sub(T m, T n) { return (m - n); } auto g_Lambda = [](int m, int n) { return (m - n); }; // 注意:匿名函数此处有分号 struct Sub { int operator()(int m, int n) { return (m - n); } }; template < class T> struct SubTemp { T operator()(T m, T n) { return (m - n); } }; class SubOper { public: static int st_sub(int m, int n) { return (m - n); } template < class T> static T temp_sub(T m, T n) { return (m - n); } double result(double m, double n) { return (m - n); } double const_result(double m, double n) const { return (m - n); } }; int main() { // 旧式写法 typedef int (*pFunc) (int, int); pFunc oldFunc = subtract; cout << "Test old style :: " << (*oldFunc)(9, 10) << endl; // -1 // [0] 包装函数指针对象 std::function cout << "Test0 :: " << from_pFunc(10, 10) << endl; // 0 // [1]包装普通函数 std::function cout << "Test1 :: " << newFunc(11, 10) << endl; // 1 // [2]包装模板函数 std::function cout << "Test2 :: " << tempFunc(12, 10) << endl; // 2 // [3]包装Lambda函数 std::function cout << "Test3 :: " << lambdaFunc(13, 10) << endl; // 3 // [4]包装仿函数 std::function cout << "Test4 :: " << objFunc(14, 10) << endl; // 4 // [5]包装模板函数对象 std::function cout << "Test5 :: " << tempFuncObj(15, 10) << endl; // 5 // [6] 类静态函数 std::function cout << "Test6 :: " << stFunc(16, 10) << endl; // 6 // [7] 类静态模板函数 std::function cout << "Test7 :: " << tempSTFunc(17, 10) << endl; // 7 // [8] 类普通函数(普通函数绑定需要依赖类对象) SubOper subOperObject; // [8.1] 使用bind,将类对象地址绑定上 std::function cout << "Test8.1 :: " << resultFunc(18.2, 10.1) << endl; // 8.1 // [8.2] 不使用bind std::function cout << "Test8.2 :: " << resultFunc2(subOperObject, 18.3, 10.1) << endl; // 8.2 // [8.3] const std::function cout << "Test8.3 :: " << const_resultFunc2(subOperObject, 18.4, 10.1) << endl; // 8.3 // [8.4] 常量对象 const SubOper subOperConst; std::function cout << "Test8.4 :: " << const_Func2(subOperConst, 18.5, 10.1) << endl; // 8.4 // [9] 应用示例(为了解耦) class TestA { public: bool destoryByName(const std::string & name) { return doDestoryByName(name); } public: std::function private: bool doDestoryByName(std::string name) { return destory_handler(name); } }; class TestB { public: bool destory(const std::string & name) { cout << "Test9 :: Call TestB destory | name : " << name << endl; return true; }; }; TestB objB; TestA objA; objA.destory_handler = [&](const std::string& name)->bool { // 摧毁操作 return objB.destory(name); }; objA.destoryByName("kaizen"); // [10] 为空时运行时异常 std::function try { if (nullptr == dealWithFunc) { throw runtime_error("std::bad_function_call"); //抛出异常 } else { dealWithFunc(100, 10); } } catch (exception e) { cout << "Test10 :: " << e.what() << endl; // 捕获异常,然后程序结束 } // [11] 作为形参类型使用 class Print { public: void doPrint(std::string content) { cout << "Test11 :: Call Print Class doPrint : " << content << endl; } }; class Person { public: Person(std::string name = {}) : m_name(name) { } void show(std::function { printFunc(m_name); } private: std::string m_name; }; // error Person oObj1{ "hello" }; //p1.show(&Print::doPrint); // 无法将参数 1 从“void (__cdecl main::Print::* )(std::string)”转换为“std::function // 方式一: std::function Print{}.doPrint(str); }; Person{"C++"}.show(printFunc1); // 方式二: Print oPrint; std::function Person{"Python"}.show(printFunc2); system("pause"); } 结果: