C++绑定器和函数对象
简介
C++ STL中的绑定器
- bind1st:operator()的第一个形参变量绑定一个确定的值。
- bind2nd:operator()的第二个形参变量绑定一个确定的值。
C++ Boost库
C++的Boost库中引入了bind
绑定器和function
函数对象机制。
lambda表达式
lambda
表达式由底层依赖函数对象的机制实现。
C++ STL中的绑定器
初识band1st和band2nd
band1st和band2nd本身还是一个函数对象。
将STL中内置的二元函数对象转化为一元函数对象使用。
#include<iostream>
#include<functional>
#include<vector>
#include<algorithm>
#include<time.h>
using namespace std;
template<typename Container>
void showContainer(Container &con){
//由于编译的原因,所以需要加上typename,防止无法识别Container类型
typename Container::iterator it = con.begin();
for (; it != con.end();it++)
{
cout << *it << " ";
}
cout << endl;
}
int main(){
vector<int> vec;
srand(time(nullptr));
for (int i = 0; i < 20;i++)
{
//产生1~100之间的随机数
vec.push_back(rand() % 100 + 1);
}
showContainer(vec);
sort(vec.begin(), vec.end());
showContainer(vec);
// greater二元函数对象,用于从大到小排序
sort(vec.begin(), vec.end(), greater<int>());
showContainer(vec);
// bind1st和bind2nd可以将二元函数对象转化为一元函数对象,也就是说传入的默认值对应二元函数对象的形参
// 寻找第一个小于70的索引,原序列按照从大到小排序 return 70>*it
// auto it = find_if(vec.begin(), vec.end(), bind1st(greater<int>(), 70));
// 寻找第一个小于70的索引,原序列按照从大到小排序 return *it<70
auto it = find_if(vec.begin(), vec.end(), bind2nd(less<int>(), 70));
if(it!=vec.end())
{
vec.insert(it, 70);
}
showContainer(vec);
return 0;
}
自己实现band1st和find_if
#include<iostream>
#include<functional>
#include<vector>
#include<algorithm>
#include<time.h>
using namespace std;
template<typename Container>
void showContainer(Container &con){
//由于编译的原因,所以需要加上typename,防止无法识别Container类型
typename Container::iterator it = con.begin();
for (; it != con.end();it++)
{
cout << *it << " ";
}
cout << endl;
}
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);
}
private:
Compare _comp;
T _val;
};
template <typename Compare, typename T>
_mybind1st<Compare, T> mybind1st(Compare comp, const T &val)
{
return _mybind1st<Compare, T>(comp, val);
}
template<typename Iterator,typename Compare>
Iterator my_find_if(Iterator first,Iterator last,Compare comp){
for (; first != last;first++){
//comp.operator()(*first)
if(comp(*first)){
return first;
}
}
return last;
}
int main(){
vector<int> vec;
srand(time(nullptr));
for (int i = 0; i < 20;i++)
{
//产生1~100之间的随机数
vec.push_back(rand() % 100 + 1);
}
showContainer(vec);
sort(vec.begin(), vec.end());
showContainer(vec);
// greater二元函数对象,用于从大到小排序
sort(vec.begin(), vec.end(), greater<int>());
showContainer(vec);
auto it = my_find_if(vec.begin(), vec.end(), mybind1st(greater<int>(), 70));
// auto it = my_find_if(vec.begin(), vec.end(), bind2nd(less<int>(), 70));
if(it!=vec.end())
{
vec.insert(it, 70);
}
showContainer(vec);
return 0;
}
bind函数
C++11中的bind绑定器的返回结果还是一个函数对象。
初识bind函数
#include<iostream>
#include<string>
#include<functional>
using namespace std;
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,world")();
cout << bind(sum, 10, 20)() << endl;
//bind使用函数对象的时候,必须要利用函数对象才能使用
cout << bind(&Test::sum, Test(), 10, 20)()<<endl;
// placeholders是占位符
bind(hello, placeholders::_1)("hello,bind2!");
bind(sum, placeholders::_1, placeholders::_2)(1, 3);
function<void(string)> func1 = bind(hello, placeholders::_1);
func1("hello,china!");
func1("hello,shanghai!");
return 0;
}
bind和function结合多线程使用
#include<iostream>
#include<string>
#include<thread>
#include<vector>
#include<functional>
using namespace std;
class Thread{
public:
Thread(function<void()> func) : _func(func){};
thread start()
{
thread t(_func);
return t;
}
private:
function<void()> _func;
};
class ThreadPool
{
public:
ThreadPool(){};
~ThreadPool(){
for (int i = 0;i<_pool.size();i++)
{
delete _pool[i];
}
};
void startPool(int size)
{
for (int i = 0; i < size; i++)
{
_pool.push_back(new Thread(bind(&ThreadPool::runThread,this,i)));
}
for (int i = 0; i < size; i++)
{
_handler.push_back(_pool[i] -> start());
}
for (int i = 0; i < size;i++)
{
_handler[i].join();
}
}
private:
vector<Thread*> _pool;
vector<thread> _handler;
void runThread(int id)
{
cout << "call run Thread id :" << id << endl;
}
};
int main()
{
ThreadPool pool;
pool.startPool(10);
return 0;
}
代码打印结果,由于是多线程,所以打印结果是乱序的。
call run Thread id :call run Thread id :call run Thread id :2call run Thread id :5
call run Thread id :61
call run Thread id :9
call run Thread id :4
call run Thread id :8
0
call run Thread id :
call run Thread id :37
C++中的lambda表达式
函数对象的主要缺点:需要先定义函数,并初始化函数对象才能被使用。
C++ 11 中的 Lambda 表达式用于定义并创建匿名的函数对象,以简化编程工作。
Lambda 的语法形式如下:
[captures](params) -> return_type { body };
Lambda 主要分为五个部分,对应为:
[捕获列表] (函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}
上式lambda表达式中->
可以省略。
捕获列表是 Lambda 表达式最有意思的地方,这里重点介绍下捕获列表。
捕获列表,用来说明外部变量的访问方式,外部变量访问方式说明符可以是 = 或 & ,表示函数体中用到的、定义在外面的变量在函数体中是否允许被改变。= 表示值传递,不允许改变。& 表示引用传递,允许改变。
包括下面几种形式:
1、[ ] 表示不捕获任何变量
2、[=] 表示按值传递的方法捕获父作用域的所有变量
3、[&] 表示按引用传递的方法捕获父作用域的所有变量
4、[=, &a] 表示按值传递的方法捕获父作用域的所有变量,但按引用传递的方法捕获变量a
5、[&, a] 表示按引用传递的方法捕获父作用域的所有变量,但按值传递的方法捕获变量a
6、[this] 捕获外部的指针
更多lambda表达式的介绍可以参考C++ 之 Lambda 表达式。
mutable
在lambda表达式返回类型前加上,可以在以值传递的形式上修改以值传递的变量值。
C++中的函数对象
function
的作用在于:绑定器、函数对象、lambda表达式,它们只能使用在一条语句中。
初识function
#include<iostream>
#include<string>
#include<algorithm>
#include<functional>
#include<ctime>
using namespace std;
void hello1()
{
cout << "hello,world!" << endl;
}
void hello2(string str)
{
cout << str << endl;
}
int sum(int a,int b){
return a + b;
}
class Test{
public:
void hello(string str){
cout << str;
}
};
int main(){
/*
function函数的使用方法,function<typename(typename1,...)> xxx=yyy;
typename表示函数的返回类型,typename_1表示寒暑的参数类型,xxx表示function重命名的函数,yyy表示原来的函数
*/
// 调用函数hello1(),function使用的是函数类型
function<void()> func1 = hello1;
// 调用函数hello1(),function使用的是函数指针类型
// function<void(*)> func1 = hello1;
// 本质上和hello1()没有区别,调用了func1对象()重载函数->hello1.operator()
func1();
function<void(string)> func2 = hello2;
func2("hello2!");
function<int(int, int)> func3 = sum;
cout << func3(10, 20) << endl;
function<int(int, int)> func4 = [](int a, int b)->int{ return a + b; };
cout << func4(10, 20);
function<void(Test*, string)> func5 = &Test::hello;
func5(&Test(), "call Test::hello!");
return 0;
}
自定义实现function
本质上是实现一个类,利用构造函数和()操作符重载的功能是实现函数绑定。
#include<iostream>
#include<functional>
#include<string>
using namespace std;
void hello(string str)
{
cout << str << endl;
}
int sum(int a,int b)
{
return a + b;
}
template<typename Fty>
class myfunction{
};
/*
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);
}
private:
PFUNC _pfunc;
};
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);
}
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...);
}
private:
PFUNC _pfunc;
};
int main(){
//就是构造函数重命名了hello函数
myfunction<void(string)> func1(hello);
func1("hello1");
myfunction<int(int, int)> func2(sum);
cout << func2(2, 3) << endl;
return 0;
}