zoukankan      html  css  js  c++  java
  • std::bind学习

    std::bind

    bind是对C++98标准中函数适配器bind1st/bind2nd的泛化和增强,可以适配任意的可调用对象,包括函数指针、函数引用、成员函数指针和函数对象。
    bind接受的第一个参数必须是一个可调用的对象f,可以是函数、函数指针、函数对象和成员函数指针,之后接受的参数的数量必须与f的参数数量相等,这些参数将被传递给f作为入参。
    绑定完成后,bind会返回一个函数对象,它内部保存了f的拷贝,具有operator(),返回值类型被自动
    推导为f的返回值类型。反生调用时,这个函数对象将把之前存储的参数转发给f完成调用。

    如:

    int Add(int num1, int num2)
    {
    	return (num1 + num2);
    }
    
    Add(1,2);
    //等价于一个具有无参operator()的bind函数对象调用
    std::bind(&Add,1,2)();
    

    这是bind最简单的形式。bind表达式存储了Add和参数1,2的拷贝,产生了一个临时的函数对象。因为Add接受两个参数,而1,2都是实参,因此临时函数对象将具有一个无参的operator()。当operator()调用发生时函数对象把1、2的拷贝传递给Add,完成真正的调用。

    bind的真正威力在与占位符,_1 _2 _3 ...,(为了避免与boost库的占位符冲突,标准占位符定义在std::placeholders名字空间,使用时:std::placeholders::_1),占位符可以取代bind中参数的位置,在发生函数调用时才接受真正的参数。

    占位符的名字表示它在调用时中的顺序,而在绑定式中没有顺序要求。如下:

    int Sub(int num1,int num2)
    {
    	return (num1 - num2);
    }
    std::bind(&Sub,std::placeholders::_1,std::placeholders::_2)(2,1);
    //等价于
    Sub(2,1);
    std::bind(&Sub,std::placeholders::_2,std::placeholders::_1)(2,1);
    //等价于
    Sub(1,2);  
    

    bind详细用法:

    //普通全局函数
    void Out( int & elem)
    {
    	std::cout << elem << " ";
    }
    
    //类
    template<typename T>
    class Print
    {
    public:
    	Print(const char * prefix = "")
    		: _prefix(prefix)
    		, _printNum(0)
    	{
    	}
    	//非静态成员函数
    	void PrintElem(const T & elem)
    	{
    		_printNum++;
    		if (_printNum <= 1)
    		{
    			cout << "
    " << _prefix << ": "; 
    		}
    		cout << elem << " ";
    	}
    	//静态成员函数
    	static void static_fun()
    	{
    		std::cout << "
    static func!";
    	}
    private:
    	string _prefix;
    	size_t _printNum;
    };
    
    int arr[] = {1,2,1,3,4,8,9,8};
    vector<int> v(arr, arr + sizeof(arr)/sizeof(arr[0]));
    

    //绑定普通函数
    std::for_each(v.begin(),v.end(),std::bind(&Out,std::placeholders::_1));
    
    //绑定类的非静态成员函数
    //第一个占位符的位置必须是一个类的实例、引用或指针
    Print<int> print("bind member function");
    std::for_each(v.begin(),v.end(),
    	std::bind(&(Print<int>::PrintElem),&print,std::placeholders::_1));
    //注:必须在成员函数前加上取地址操作符&,表明这是一个成员函数指针,否则会无法通过编译。
    
    //绑定静态成员函数 与绑定全局函数没有区别
    std::function<void(void)> ff = std::bind(&Print<int>::static_fun);
    ff();
    

    绑定函数对象:

    bind可以绑定任意的函数对象,包括标准库中的所有预定义的函数对象。
    如果函数对象有内部类型定义result_type,那么bind可以自动推导出返回值类型,用法与绑定普通函数一样。否则,需要在绑定形式上做出变动,用模版参数指明返回类型。
    bind<result_type>(functiontor, ...)

    标准库中大部分函数对象都有result_type定义,因此不需要特别的形式。

    //绑定预定义的函数对象
    std::transform(v.begin(),v.end(),v.begin(),
    		std::bind(std::plus<int>(),std::placeholders::_1,10)); //绑定函数对象
    
    
    //绑定自定义的函数对象
    //要想bind 绑定自定义的函数对象,必须提供一些型别的成员来反映其参数和返回值的型别, 
    //为了方便,可以继承 binary_function等
    template<typename T1, typename T2>
    struct fopow : public std::binary_function<T1,T2,T1>
    {
    	T1 operator() (T1 base, T2 exp) const
    	{
    		return std::pow(base,exp);
    	}
    };
    std::transform(v.begin(),v.end(),v.begin(),
    	std::bind(fopow<double,int>(),std::placeholders::_1,2));
    
    //自己定义result_type
    template<typename T>
    struct MyPlus
    {
    	typedef T argument_type;
    	typedef T result_type;
    	result_type operator() (const argument_type & arg1, const argument_type & arg2) const
    	{
    		return (arg1 - arg2);
    	}
    };
    
    std::function<int(int)> f = std::bind(MyPlus<int>(),std::placeholders::_1,10);
    std::transform(v.begin(),v.end(),v.begin(),f);
    

    补充:

    //binary_function原型
    
    template<class _Arg1,
    class _Arg2,
    class _Result>
    struct binary_function
    {	// base class for binary functions
    typedef _Arg1 first_argument_type;
    typedef _Arg2 second_argument_type;
    typedef _Result result_type;
    };
    

    关于std::function,可以参考C++11中的std::function这篇文章。

  • 相关阅读:
    数据库
    linux
    linux
    python_函数进阶1
    python_函数初识
    python_文件操作
    python_基础数据类型补充
    python 小数据池,代码块总览
    python_基础数据类型二
    python_基础数据类型一
  • 原文地址:https://www.cnblogs.com/cmranger/p/4743926.html
Copyright © 2011-2022 走看看