C/C++教程

C++ bind和function

本文主要是介绍C++ bind和function,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

bind1st 和bind2nd

bind1st : operator()的第一个形参变量绑定成一个确定的值
bind2nd : operator()的第二个形参变量绑定成一个确定的值

实例:

将数组从大到小排序后,按顺序插入70

#include <iostream>
#include <vector> 
#include <functional>
#include <algorithm>
#include <ctime>
using namespace std;

template<typename Container>
void showContainer(Container& con)
{
  typename Container::iterator it = con.begin();
  //编译器是从上到下编译的,这个还没有实例化,它不知道这个名字作用域后面的iterator是类型还是变量
  //typename告知编译器后面类型的作用域后面是类型
  for (; it != con.end(); ++it)
  {
    cout << *it << " ";
  }
  cout << endl;
}

int main()
{
  vector<int> vec;
  srand(time(nullptr));
  for (int i = 0; i < 10; ++i)
  {
    vec.push_back(rand() % 100 + 1);//随机出来的数字,并不是有序的 
  }

  showContainer(vec);

  //greater 二元函数对象
  sort(vec.begin(), vec.end(), greater<int>());//大到小排序
  showContainer(vec);

  //把70按顺序插入到vec容器当中,找第一个小于70的数字
  auto it1 = find_if(vec.begin(), vec.end(),
    bind1st(greater<int>(), 70));
  //auto it1 = find_if(vec.begin(), vec.end(),bind2nd(less<int>(), 70));
  if (it1 != vec.end())
  {
    vec.insert(it1, 70);
  }
  showContainer(vec);
  return 0;
}

实现原理

find_if的源码;

		// FUNCTION TEMPLATE find_if
template<class _InIt,
	class _Pr>
	_NODISCARD inline _InIt find_if(_InIt _First, const _InIt _Last, _Pr _Pred)
	{	// find first satisfying _Pred
	_Adl_verify_range(_First, _Last);
	auto _UFirst = _Get_unwrapped(_First);
	const auto _ULast = _Get_unwrapped(_Last);
	for (; _UFirst != _ULast; ++_UFirst)
		{
		if (_Pred(*_UFirst))
			{
			break;
			}
		}

	_Seek_wrapped(_First, _UFirst);
	return (_First);
	}

其中第三个参数_Pred是一个一元函数对象

bind1st源码

		// FUNCTION TEMPLATE bind1st
template<class _Fn,
	class _Ty>
	_NODISCARD inline binder1st<_Fn> bind1st(const _Fn& _Func, const _Ty& _Left)
	{	// return a binder1st functor adapter
	typename _Fn::first_argument_type _Val(_Left);
	return (binder1st<_Fn>(_Func, _Val));
	}

它是一个函数模板,返回一元函数对象binder1st

binder1st

		// CLASS TEMPLATE binder1st
template<class _Fn>
	class binder1st
		: public unary_function<typename _Fn::second_argument_type,
			typename _Fn::result_type>
	{	// functor adapter _Func(stored, right)
public:
	typedef unary_function<typename _Fn::second_argument_type,
		typename _Fn::result_type> _Base;
	typedef typename _Base::argument_type argument_type;
	typedef typename _Base::result_type result_type;

	binder1st(const _Fn& _Func,
		const typename _Fn::first_argument_type& _Left)
		: op(_Func), value(_Left)
		{	// construct from functor and left operand
		}

	result_type operator()(const argument_type& _Right) const
		{	// apply functor to operands
		return (op(value, _Right));
		}

	result_type operator()(argument_type& _Right) const
		{	// apply functor to operands
		return (op(value, _Right));
		}

protected:
	_Fn op;	// the functor to apply
	typename _Fn::first_argument_type value;	// the left operand
	};

一元函数对象默认构造函数接受两个参数, op和 value。赋值运算符接收一个参数,并使用传入的op和vaule 进行运算:op(value, _Right)

简单的实现如下:

#include <iostream>
#include <vector> 
#include <functional>
#include <algorithm>
#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;
}

template<typename Iterator, typename Compare>
Iterator my_find_if(Iterator first, Iterator last, Compare comp)
//遍历这2个迭代器之间的元素,如果满足函数对象的运算,就返回当前迭代器,如果都不满足,返回end()
{
  for (; first != last; ++first)
  {
    if (comp(*first))//comp.operator()(*first)一元函数对象,因为要从容器拿1个元素和它指定的元素比较
    //my_find_if需要1元函数对象,而在库里面都是二元的
    {
      return first;
    }
  }
  return last;
}

template<typename Compare, typename T>
class _mybind1st//绑定器是函数对象的一个应用
{
public:
  _mybind1st(Compare comp, T val)
    :_comp(comp), _val(val)
  {}
  bool operator()(const T& second)
  {
    return _comp(_val, second);//greater
  }
private:
  Compare _comp;
  T _val;
};

//mybind1st(greater<int>(), 70)
template<typename Compare, typename T>
_mybind1st<Compare, T> mybind1st(Compare comp, const T& val)
{
  //直接使用函数模板,好处是,可以进行类型的推演
  return _mybind1st<Compare, T>(comp, val);
}

int main()
{
  vector<int> vec;
  srand(time(nullptr));
  for (int i = 0; i < 20; ++i)
  {
    vec.push_back(rand() % 100 + 1);
  }

  showContainer(vec);


  //greater 二元函数对象
  sort(vec.begin(), vec.end(), greater<int>());//大到小排序
  showContainer(vec);

  /*
  把70按顺序插入到vec容器当中   找第一个小于70的数字
  operator()(const T &val)
  greater   a > b
  less      a < b
  绑定器 + 二元函数对象 =》 一元函数对象
  bind1st: + greater bool operator()(70, const _Ty& _Right)
  bind2nd: + less bool operator()(const _Ty& _Left, 70)
  */

  auto it1 = my_find_if(vec.begin(), vec.end(),
    mybind1st(greater<int>(), 70));
  //auto it1 = my_find_if(vec.begin(), vec.end(),bind2nd(less<int>(), 70));
  if (it1 != vec.end())
  {
    vec.insert(it1, 70);
  }
  showContainer(vec);

  return 0;
}

function

解决绑定器,函数对象,lambda表达式只能使用在一条语句中的问题;

定义:传递一个  _Fty  function type 希望传递一个函数类型

	// CLASS TEMPLATE function
template<class _Fty>
	class function
		: public _Get_function_impl<_Fty>::type
	{	// wrapper for callable objects
private:
	typedef typename _Get_function_impl<_Fty>::type _Mybase;

public:
	function() noexcept
		{	// construct empty function wrapper
		}

简单使用:

#include <iostream>
#include <vector> 
#include <functional>
#include <algorithm>
#include <ctime>
#include <string>
using namespace std;

void hello1()
{
  cout << "hello world!" << endl;
}
void hello2(const string &str)//void (*pfunc)(string)
{
  cout << str << endl;
}
int sum(int a, int b)
{
  return a + b;
}

class Test
{
public://必须依赖一个对象void (Test::*pfunc)(string)
  void hello(string str) { cout << str << endl; }
};

int main()
{
  /*
  1.用函数类型实例化function
  2.通过function调用operator()函数的时候,需要根据函数类型传入相应的参数
  */

  //从function的类模板定义处,看到希望用一个函数类型实例化function
  function<void()> func1 = hello1;
  func1();//func1.operator()() => hello1()

  function<void(string)> func2 = hello2;
  func2("hello hello2!");//func2.operator()(string str) => hello2(str)

  function<int(int, int)> func3 = sum;
  cout << func3(20, 30) << endl;

  //operator()  lambda 表达式
  function<int(int, int)> func4 = [](int a, int b)->int {return a + b; };
  cout << func4(100, 200) << endl;

  //类成员函数
  function<void(Test*, string)> func5 = &Test::hello;
  func5(&Test(), "call Test::hello!");//临时对象调用

  return 0;
}

模板的完全特例化和部分特例化

        对于下面的compare,对于char类型的比较不能满足实际的需要,因此对compare特例化一个版本compare<const char *>

#include <iostream>
#include <vector> 
#include <functional>
#include <algorithm>
#include <ctime>
#include <string>
using namespace std;

template<typename T>
bool compare(T a, T b)
{
  cout << "template compare" << endl;
  return a > b;
}
template<>
bool compare<const char*>(const char*a, const char*b)//特例化 
{
  cout << "compare<const char*>" << endl;
  return strcmp(a, b) > 0;
}
int main()
{
  compare(10, 20);// 
  compare("aaa", "bbb");//T const char*
  return 0;
}

匹配原则:有完全特例化则先匹配完全特例化,其次部分特例化,最后函数模板

#include <iostream>
#include <vector> 
#include <functional>
#include <algorithm>
#include <ctime>
#include <string>
using namespace std;

//类模板
template<typename T>
class Vector
{
public:
  Vector() { cout << "call Vector template init" << endl; }
};

//下面这个是对char*类型提供的完全特例化版本(<>中T已知:即下面的char *)  #1 
template<>//特例化的语法
class Vector<char*>
{
public:
  Vector() { cout << "call Vector<char*> init" << endl; }
};

//下面这个是对指针类型提供的部分特例化版本  #2
//仅知道是一个指针,类型需要提供
template<typename Ty>
class Vector<Ty*>
{
public:
  Vector() { cout << "call Vector<Ty*> init" << endl; }
};

//指针函数指针(有返回值,有两个形参变量)提供的部分特例化
template<typename R, typename A1, typename A2>
class Vector<R(*)(A1, A2)>
{
public:
  Vector() { cout << "call Vector<R(*)(A1, A2)> init" << endl; }
};

//针对函数(有一个返回值,有两个形参变量)类型提供的部分特例化
template<typename R, typename A1, typename A2>
class Vector<R(A1, A2)>
{
public:
  Vector() { cout << "call Vector<R(A1, A2)> init" << endl; }
};

int sum(int a, int b) { return a + b; }
int main()
{
  Vector<int> vec1;
  Vector<char*> vec2;
  Vector<int*> vec3;
  Vector<int(*)(int, int)> vec4;
  Vector<int(int, int)> vec5;//function

  //注意区分一下函数类型和函数指针类型
  typedef int(*PFUNC1)(int, int);
  PFUNC1 pfunc1 = sum;
  cout << pfunc1(10, 20) << endl;

  typedef int PFUNC2(int, int);
  PFUNC2 *pfunc2 = sum;
  cout << (*pfunc2)(10, 20) << endl;

  return 0;
}

实参推演:

 

#include <iostream>
#include <typeinfo>
using namespace std;


int sum(int a, int b) { return a + b; }

//T包含了所有的大的类型  返回值,所有形参的类型都取出来
template<typename T>
void func(T a)
{
  cout << typeid(T).name() << endl;
}

//细化返回值类型和参数类型
template<typename R, typename A1, typename A2>
void func2(R(*a)(A1, A2))
{
  cout << typeid(R).name() << endl;
  cout << typeid(A1).name() << endl;
  cout << typeid(A2).name() << endl;
}

class Test
{
public:
  int sum(int a, int b) { return a + b; }
};

//实参推演每一个类型
template<typename R, typename T, typename A1, typename A2>
void func3(R(T::* a)(A1, A2))
{
  cout << typeid(R).name() << endl;
  cout << typeid(T).name() << endl;
  cout << typeid(A1).name() << endl;
  cout << typeid(A2).name() << endl;
}
int main()
{
  func(10);
  func("aaa");
  func(sum);//T  int (*)(int,int)   int (int,int)
  func(&Test::sum);//int (__thiscall Test::*)(int,int)
  
  //
  cout << "---------------------func2\n";
  func2(sum);

  cout << "---------------------func3\n";
  func3(&Test::sum);//int (__thiscall Test::*)(int,int)

  return 0;
}

 function 原理剖析

#include <iostream>
#include <typeinfo>
#include <string>
#include <functional>
using namespace std;

/*
function函数对象类型的实现原理
*/
void hello(string str) { cout << str << endl; }
int sum(int a, int b) { return a + b; }

//定义个函数模板
template<typename Fty>
class myfunction {};


//部分偏特化版本  <R(A1)
template<typename R, typename A1>
class myfunction<R(A1)>
{
public:
  using PFUNC = R(*)(A1);
  myfunction(PFUNC pfunc) :_pfunc(pfunc) {}
  R operator()(A1 arg)
  {
    return _pfunc(arg);//hello(arg)
  }
private:
  PFUNC _pfunc;
};

/*
//部分偏特化版本   R(*)(A1, A2);
template<typename R, typename A1, typename A2>
class myfunction<R(A1, A2)>
{
public:
  using PFUNC = R(*)(A1, A2);
  myfunction(PFUNC pfunc) :_pfunc(pfunc) {}
  R operator()(A1 arg1, A2 arg2)
  {
    return _pfunc(arg1, arg2);//hello(arg)
  }
private:
  PFUNC _pfunc;
};
*/
//通用版本
template<typename R, typename... A>//一组可变参数个数:表示一组类型
class myfunction<R(A...)>
{
public:
  using PFUNC = R(*)(A...);
  myfunction(PFUNC pfunc) :_pfunc(pfunc) {}
  R operator()(A... arg)//一组形参变量
  {
    return _pfunc(arg...);//hello(arg) 表示一组形参变量
  }
private:
  PFUNC _pfunc;
};

int main()
{
  myfunction<void(string)> func1(hello);
  func1("hello world!");//func1.operator()("hello world!")

  myfunction<int(int, int)> func2(sum);
  cout << func2(10, 20) << endl;

  return 0;
}

fuction 底层是一个可变参的偏特化函数对象

bind

C++11 bind绑定器,是一个函数模板 ,可以自动推演模板类型参数=> 返回的结果还是一个函数对象
bind占位符最多有20个参数

#include <iostream>
#include <typeinfo>
#include <string>
#include <memory>
#include <vector>
#include <functional>
#include <thread>
using namespace std;
using namespace placeholders;

/*
C++11 bind绑定器 => 返回的结果还是一个函数对象
*/

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是函数模板 可以自动推演模板类型参数
  bind(hello, "hello bind!")();//返回的结果是绑定器,也就是函数对象 最后一个()表示调用函数对象的operator() 
  cout << bind(sum, 10, 20)() << endl;
  cout << bind(&Test::sum, Test(), 20, 30)() << endl;

  //参数占位符  绑定器出了语句,无法继续使用
  //只是占位的作用,调用的时候就要传递参数了 
  //书写的时候使用多少个占位符,就是意味着用户调用的时候要传入几个参数
  bind(hello, placeholders::_1)("hello bind 2!");
  cout << bind(sum, placeholders::_1, placeholders::_2)(200, 300) << endl;

  //此处把bind返回的绑定器binder就复用起来了
  function<void(string)> func1 = bind(hello, _1);
  func1("hello china!");
  func1("hello shan xi!");
  func1("hello si chuan!");

  return 0;
}

placeholders 占位符:最多支持20个

 

这篇关于C++ bind和function的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!