c++11之functionbind

Posted ych9527

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++11之functionbind相关的知识,希望对你有一定的参考价值。

1.function

1.1function简介

  • 类模板std :: function是一个通用的多态函数包装器

  • std :: function的实例可以存储,复制和调用任何可调用的目标 :包括函数,lambda表达式,绑定表达式或其他函数对象,以及指向成员函数和指向数据成员的指针

  • 当std::function对象未包裹任何实际的可调用元素,调用该std::function对象将抛出std::bad_function_call异常

  • std::function
    template <class T> function;     // undefined
    template <class Ret, class... Args> class function<Ret(Args...)>;
    
    Ret:被调用函数的返回值
    Args...:可变参数列表    
    
  • 例子:

    • function<int<int,int>>func 表示func可以指向返回值为int,并且有两个int参数的函数

1.2演示

  • 包装普通函数、仿函数、成员函数演示
void func1()
{
	cout << "普通函数" << endl;
}

struct Test
{
	void operator () (int val1,double val2)
	{
		cout << "仿函数:"<<val1<<" "<<val2<< endl;
	}
};

struct Obj
{
	static void func2()
	{
		cout << "静态成员函数" << endl;
	}

	void func3()
	{
		cout << "非静态成员函数" << endl;
	}
};



int main()
{

	function<void()> f1 = func1;
	function<void(int,double)> f2 = Test();
	function<void()> f3 = Obj::func2;
	function<void(Obj)> f4 = &Obj::func3;//非静态成员函数,需要传入一个对象&&显示的取地址
	function<void(int a ,int b,int c)> f5 = [](int a,int b,int c){cout << "lambda表达式:"<<a+b+c<< endl; };

	f1();
	f2(10,12.12);
	f3();
	f4(Obj());//传入一个匿名对象
	f5(10,20,30);

  • operator bool

    • 一个类实现operator bool ,就可以让类对象直接去做逻辑真假的判断

1.3作用

  • 在某些场景下,可以减少模板实例化的次数,提高模板的效率
//模板函数
template<class F>
void Print(F fun)
{
	static int count = 0;//静态的

	cout <<"count_val:" <<++count << endl;
	cout <<"count_address:" <<&count << endl;

}

void func1()
{
	cout << "普通函数" << endl;
}

struct Test
{
	void operator () ()
	{
		cout << "仿函数:"<< endl;
	}
};

struct Obj
{
	static void func2()
	{
		cout << "静态成员函数" << endl;
	}

	void func3()
	{
		cout << "非静态成员函数" << endl;
	}
};



int main()
{

	function<void()> f1 = func1;
	function<void()> f2 = Test();
	function<void()> f3 = Obj::func2;
	function<void(Obj)> f4 = &Obj::func3;//非静态成员函数,需要传入一个对象&&显示的取地址
	function<void()> f5 = [](){cout << "lambda表达式:"<< endl; };
	auto fun4 = [](){cout << "lambda表达式:" << endl; };

	cout << "---------直接调用------------" << endl<<endl;
	Print(func1);
	Print(Test());
	Print(Obj::func2);
	Print(&Obj::func3);
	Print(fun4);

	cout << "---------封装后调用------------" << endl;
	Print(f1);
	Print(f2);
	Print(f3);
	Print(f4);
	Print(f5);

1.4应用

逆波兰表达式

class Solution {
public:
    int evalRPN(vector<string>& tokens) {

        //第二个函数类型包装一下,作为map的v值类型
        //包装的是lambda表达式
        //比如K值是+ op[+]返回的是一个lambda表达式,传入对应的数值即可
        unordered_map<string,function<int(int,int)>> op=
        {
            {"+",[](int a,int b) ->int{return a+b;}},
            {"-",[](int a,int b) ->int{return a-b;}},
            {"*",[](int a,int b) ->int{return a*b;}},
            {"/",[](int a,int b) ->int{return a/b;}}
        };

         stack<int> st;
         for(auto&e:tokens)
         {
             if(e=="+" || e=="-" || e=="*" ||e=="/")
             {
                 int n1=st.top();
                 st.pop();
                 int n2=st.top();
                 st.pop();
                st.push(op[e](n2,n1));
             }
             else
                st.push(stoi(e));
         }

        return st.top();
    }
};

2.bind

2.1bind简介

  • template <class Fn, class... Args>
        bind (Fn&& fn, Args&&... args);
    
    template <class Ret, class Fn, class... Args>
    	bind (Fn&& fn, Args&&... args)
    
    • fn:一个可调用对象(可以是函数对象、函数指针、函数引用、成员函数指针、数据成员指针)
    • 它的参数将被绑定到args上args:绑定参数列表,参数会被值或占位符替换,其长度必须与f接收的参数个数一致。
  • std::bind函数定义在头文件functional中,是一个函数模板,它就像一个函数适配器,接受一个可调用对象(callable object),生成一个新的可调用对象来**“适应”原对象的参数列表**

  • 一般而言,我们用它可以把一个原本接收N个参数的函数func,通过绑定一些参数,返回一个接收M个参数的新函数。同时,使用std::bind函数还可以实现参数顺序调整等操作

  • 调用bind的一般形式:auto newfunc=bind(func,arg_list)

    • 其中,newfunc本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的func的参数。当我们调用newfunc时,newfunc会调用func,并传给它arg_list中的参数
    • _arg_list中的参数可能包含形如_n的名字,其中n是一个整数,这些参数是“占位符”,表示newfunc的参数,它们占据了传递给newCallable的参数的“位置”。数值n表示生成的可调用对象中参数的位置:_1为newCallable的第一个参数,_2为第二个参数,以此类推

2.2绑定的价值

#include "test.h"
int Add(int x, int y)
{
	return x + y;
}

struct Sub
{
	int sub(int x, int y)
	{
		return x - y;
	}
};

int main()
{
	//bind的返回值类型就是function
	function<int(int, int)> func1 = bind(Add, placeholders::_1, placeholders::_2);
	auto func2 = bind(Add, placeholders::_1, placeholders::_2);

	cout <<"function<int(int, int)> func1"<<" "<<func1(10, 20) << endl;
	cout <<"auto func2" <<" "<<func2(10, 20) << endl<<endl;

	
	//正常function用法每次需要传入对象
	function<int(Sub, int, int)> func3 = &Sub::sub;
	cout <<"正常function用法"<<func3(Sub(),11, 22) << endl;

	//绑定后可以不传入对象
	function<int(int, int)> func4 =bind(&Sub::sub,Sub(),placeholders::_1,placeholders::_2);
	cout <<"绑定后不传对象:" <<func4(11, 22) << endl;

	//绑定后,可以更换参数位置
	function<int(int, int)> func5 = bind(&Sub::sub, Sub(), placeholders::_2, placeholders::_1);
	cout << "绑定后,可以更换参数位置:" << func5(11, 22) << endl;
  • 调用类的成员函数的时候,绑定后,可以不传入对象
  • 可以更换参数的位置

以上是关于c++11之functionbind的主要内容,如果未能解决你的问题,请参考以下文章

C++高级开发之可调用对象functionbind

C++高级开发之可调用对象functionbind

转载C++ functionbind和lambda表达式

C++11特性之std:call_once介绍

以下代码片段 C++ 的说明

面向面试编程代码片段之GC