ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C++ bind和function

2021-11-28 17:02:49  阅读:110  来源: 互联网

标签:function return cout bind C++ vec const include


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个

 

标签:function,return,cout,bind,C++,vec,const,include
来源: https://blog.csdn.net/LIJIWEI0611/article/details/121461643

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有