- C++ STL中的绑定器
bind1st : operator()的第一个形参变量绑定成一个确定的值 bind2nd : operator()的第二个形参变量绑定成一个确定的值 - (C++11从Boost库中引入了)bind绑定器和function函数对象机制
- lambda表达式 底层依赖函数对象的机制实现的
#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
#include <ctime>
using namespace std;
template<typename Container>
void showContainer(Container &con)
{
// Container没有实例化需要在前面加上typename实例化=>告知编译器Container::iterator是个类型
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)
{
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);
/*
做一个功能:
把70按顺序插入到vec容器当中 => 找第一个小于70的数字
operator()(const T &val) <= 只需要接收一个参数,STL库里的是二元函数对象
greater a > b
less a < b
绑定器 + 二元函数对象 => 一元函数对象
bind1st: + greater bool operator()(70, const _Ty& _Right) => 使用sort中的greater
bind2nd: + less bool operator()(const _Ty& _Left, 70) => 使用sort中的less,绑定第二个参数
*/
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;
}
注意到下面代码实现了把70按顺序插入到vec容器当中。
auto it1 = find_if(vec.begin(), vec.end(),
bind1st(greater<int>(), 70));
源码文件里还有对其底层实现的讲解,就不赘述了。(我也还不太懂)
注: bind1st和bind2nd已经废弃了,只能作为学习
C++11提供的绑定器和函数对象 bind function C++ STL bind1st和bind2nd => 本身还是一个函数对象 function : 绑定器,函数对象,lambda表达式 => 它们只能使用在一条语句中(局限) 当在多条语句中应用时,需要function => 留下绑定器,函数对象,lambda表达式这些的类型
function和C语言的函数指针类似,但是其功能更丰富可以和类更深度的结合。
#include <iostream>
#include <vector>
#include <map>
#include <functional> // 使用function函数对象类型
#include <algorithm>
#include <ctime>
#include <string>
using namespace std;
void hello1()
{
cout << "hello world!" << endl;
}
void hello2(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; // 返回值是void,()代表没有参数
func1(); // func1.operator()() => hello1()
function<void(string)> func2 = hello2; // 返回值是void,(string)代表函数有一个string类型的参数
func2("hello hello2!"); // func2.operator()(string str) => hello2(str)
function<int(int, int)> func3 = sum;
cout<<func3(20, 30)<<endl;
// operator()
function<int(int, int)> func4 = [](int a, int b)->int {return a + b; }; // 参数是(int a, int b),->int代表返回值是int型
cout << func4(100, 200) << endl;
// function成员方法调用需要依赖对象Test*相当于类的this指针
function<void(Test*, string)> func5 = &Test::hello;
func5(&Test(), "call Test::hello!");
return 0;
}
bind绑定器实现了将一个或多个参数绑定到函数对象(function).
说白了就是给调用函数对象并对其参数赋值。
总共有三种使用方式:
- 直接调用
#include <iostream>
#include <typeinfo>
#include <string>
#include <functional>
using namespace std;
using namespace placeholders; // bind占位符参数的作用域
void hello(string str) { cout << str << endl; }
int main()
{
bind(hello, "hello bind!")();
}
上述代码输出hello bind!
- bind + 占位符实现带参数调用的bind
在上面的代码的main函数中新增如下代码
bind(hello, placeholders::_1)("hello bind 2!");
注意此时的bind是可以待参数的,参数传入到占位符中,如果要对第二个参数赋值则是使用占位符placeholders::_2
,以此类推。
此时代码输出"hello bind 2!"
- 使用function来复用bind
上面的代码还缺少复用bind的能力,在上面main函数中新增代码如下:
function<void(string)> func1 = bind(hello, _1);
func1("hello func!");
std::string tmp = "hello str!";
func1(tmp);
代码输出:
hello func!
hello str!
下面是一个更完整的用例。
#include <iostream>
#include <typeinfo>
#include <string>
#include <functional>
using namespace std;
using namespace placeholders; // bind占位符参数的作用域
/*
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调用时需要绑定所有参数
bind(hello, "hello bind!")();
cout << bind(sum, 10, 20)() << endl;
cout << bind(&Test::sum, Test(), 20, 30)() << endl; // 调用类里的函数需要对象
// bind + 参数占位符
bind(hello, _1)("hello bind 2!");
cout << bind(sum, _1, _2)(200, 300) << endl;
// 上面存在一个问题:bind出了语句无法使用,没办法复用
// function + 参数占位符 解决 => 绑定器出了语句,无法继续使用
// 此处把bind返回的绑定器binder就复用起来了
function<void(string)> func1 = bind(hello, _1);
func1("hello china!");
func1("hello shan xi!");
func1("hello si chuan!");
return 0;
}
#include <iostream>
#include <typeinfo>
#include <string>
#include <memory>
#include <vector>
#include <functional>
#include <thread>
using namespace std;
using namespace placeholders;
/*
muduo源码文件 threadpool.cc thread.cc bind function
*/
// 线程类
class Thread
{
public:
Thread(function<void(int)> func, int no) :_func(func), _no(no) {} // 用函数对象类型来接受绑定器类型
thread start() // 创建线程
{
thread t(_func, _no); // _func(_no)
return t;
}
private:
function<void(int)> _func;
int _no;
};
// 线程池类
class ThreadPool
{
public:
ThreadPool() {}
~ThreadPool()
{
// 释放Thread对象占用的堆资源
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::runInThread, this, _1), i)); // bind返回的是函数对象,i通过_1占位符(Thread类里的_no)传入
}
for (int i = 0; i < size; ++i)
{
_handler.push_back(_pool[i]->start()); // 调用每一个线程对象的start方法
}
for (thread &t : _handler)
{
t.join(); // 等待所有子线程运行完成
}
}
private:
vector<Thread*> _pool; // 线程池
vector<thread> _handler; // 线程实例(句柄)
// 把runInThread这个成员方法充当线程函数 thread pthread_create
void runInThread(int id)
{
cout << "call runInThread! id:" << id << endl;
}
};
int main()
{
ThreadPool pool;
pool.startPool(10);
return 0;
}