bind用于绑定可调用 (Callable) 对象(函数对象、指向函数指针、到函数引用、指向成员函数指针或指向数据成员指针)和其参数。返回值为绑定成功后的函数对象。
在正式开始绑定器前,先进行一下知识补充。
函数对象是可以以函数方式与()结合使用的任意对象,包括:(functor-仿函数)
1、函数名;
2、指向函数的指针;
3、重载了()操作符的类对象(即定义了函数operator()()的类)。
转自:https://www.jianshu.com/p/1c986b510cff
一元函数:函数的参数只有一个;
一元断言/一元谓词:函数的参数只有一个,并且返回类型是bool类型。
二元函数:函数的参数有两个;
二元断言/二元谓词:函数的参数两个,并且返回类型是bool类型。
//一元函数
int func(int b) { return b; }
//一元断言/一元谓词
bool func(int a) { return a>1; }
对于一元和二元断言,可以使用bind1st与bind2nd绑定。
template< class F, class T > std::binder1st<F> bind1st( const F& f, const T& x );
template< class F, class T > std::binder2nd<F> bind2nd( const F& f, const T& x );
#include
#include
#include
#include
#include
using std::cout;
using std::endl;
using std::remove_if;
using std::copy;
using std::vector;
using std::ostream_iterator;
void test()
{
vector<int> number = { 1, 5, 7, 9, 4, 6, 2, 8 };
//copy函数将容器拷贝到输出迭代器中。
copy(number.begin(), number.end(), ostream_iterator<int>(cout, " "));
cout << endl;
//remove_if仅仅将符合条件的元素放到容器头部排列,返回一个指向需删除元素的位置的迭代器。故还需要erase将无关元素删除。
number.erase(remove_if(number.begin(), number.end(), bind2nd(std::greater<int>(), 4)), number.end());
//auto it = remove_if(number.begin(), number.end(), bind2nd(std::greater(), 4));
//number.erase(it, number.end());
copy(number.begin(), number.end(), ostream_iterator<int>(cout, " "));
cout << endl;
/*
1 5 7 9 4 6 2 8
1 4 2
*/
}
int main(int argc, char** argv)
{
test();
return 0;
}
头文件#include ,形式为std::placeholders::_n,占位符整体代表的是形参的位置,占位符中的数字代表的是实参的位置。
void func4(int x1, int x2, int x3, const int& x4, int x5)
{
cout << "x1 = " << x1 << endl
<< "x2 = " << x2 << endl
<< "x3 = " << x3 << endl
<< "x4 = " << x4 << endl
<< "x5 = " << x5 << endl;
}
void test3()
{
int number = 10;
//bind采用的是值传递
//ref = reference, 引用的包装器
//cref = const reference, 引用的包装器
auto f = bind(func4, 1, std::placeholders::_3, std::placeholders::_1, std::cref(number), number);
number = 30;
f(50, 40, 60, 70, 90, 80);//没有用到的参数就丢掉
/*
x1 = 1 直接传入的参数
x2 = 60 实参列表第三位
x3 = 50 实参列表第一位
x4 = 30 number的引用,后续更改为30
x5 = 10 传参时number的值
*/
}
bind函数的使用相比于bind1st以及bind2nd更加的具有通用性,因为后者只能绑定一个参数,而bind可以绑定任意个参数。
#include
#include
using std::cout;
using std::endl;
using std::bind;
using std::function;
int add(int a, int b)
{
cout << "int add(int, int)" << endl;
return a + b;
}
class Example
{
public:
int add(int a, int b)
{
cout << "int Example::add(int, int)" << endl;
return a + b;
}
int data = 100;//C++11的初始化方式
};
void test()
{
//function与bind结合使用,就可以实现多态
//bind可以绑定add,可以改变函数add的形态(类型)
//int(int, int)--->int()
//函数也是有类型的(函数返回类型与函数的参数列表)
/* auto f = bind(add, 1, 2); */
function<int()> f = bind(add, 1, 2);
cout << "f() = " << f() << endl;
Example ex;
//成员函数要取地址,需要明确写出取地址符号
//int(int, int)--->int(int)
/* auto f2 = bind(&Example::add, ex, 3, 5); */
function<int()> f2 = bind(&Example::add, ex, 3, 5);
cout << "f2() = " << f2() << endl;
//占位符
//int(int, int)--->int(int)
/* auto f3 = bind(add, 4, std::placeholders::_1); */
function<int(int)> f3 = bind(add, 4, std::placeholders::_1);
cout << "f3(5) = " << f3(5) << endl;
//bind可以绑定数据成员
//int data = 100;
f = bind(&Example::data, &ex);
cout << "f() = " << f() << endl;
/*
int add(int, int)
f() = 3
int Example::add(int, int)
f2() = 8
int add(int, int)
f3(5) = 9
f() = 100
*/
}
int main(int argc, char** argv)
{
test();
return 0;
}
#include
#include
#include
using std::cout;
using std::endl;
using std::bind;
using std::function;
class Rectangle
{
public:
Rectangle(double length = 0, double width = 0)
: _length(length)
, _width(width)
{
cout << "Rectangle(double = 0, double = 0)" << endl;
}
void display() const
{
cout << "Rectangle : ";
}
double area() const
{
return _length * _width;
}
~Rectangle()
{
cout << "~Rectangle()" << endl;
}
private:
double _length;
double _width;
};
class Circle
{
public:
Circle(double radius = 0)
: _radius(radius)
{
cout << "Ciecle(double)" << endl;
}
void print() const
{
cout << "Circle: print()" << endl;
}
double printArea() const
{
return _radius * _radius * 3.1415;
}
~Circle()
{
cout << "~Circle()" << endl;
}
private:
double _radius;
};
class Triangle
{
public:
Triangle(double a = 0, double b = 0, double c = 0)
: _a(a)
, _b(b)
, _c(c)
{
cout << "Triangle(double = 0, double = 0, double = 0)" << endl;
}
void show() const
{
cout << "Triangle: ";
}
double showArea() const
{
double tmp = (_a + _b + _c) / 2;
return sqrt(tmp * (tmp - _a) * (tmp - _b) * (tmp - _c));
}
~Triangle()
{
cout << "~Triangle()" << endl;
}
private:
double _a;
double _b;
double _c;
};
class Figure
{
public:
//重定义
/* typedef function DisplayCallback;//C */
using DisplayCallback = function<void()>;//C++11
using AreaCallback = function<double()>;
DisplayCallback _displayCallback;
AreaCallback _areaCallback;
//回调函数的注册
void setDisplayCallback(const DisplayCallback& call)
{
_displayCallback = call;
}
void setAreaCallback(AreaCallback&& call)
{
_areaCallback = std::move(call);
}
//回调函数的执行
void handleDisplayCallback() const
{
if (_displayCallback)
{
_displayCallback();
}
}
double handleAreaCallback() const
{
if (_areaCallback)
{
return _areaCallback();
}
else
{
return 0;
}
}
};
void func(const Figure& fig)
{
fig.handleDisplayCallback();
cout << "area : " << fig.handleAreaCallback() << endl;
}
int main(void)
{
Circle circle(10);
cout << endl;
Figure fig;
//通过Figure类对象对不同的类进行托管,Figure类类似多继承中的基类。
//bind绑定类内的成员和this指针后,返回绑定成功的类匿名对象,让函数指针_displayCallback指向其匿名对象。
//之后即可通过函数指针来执行类内的成员函数,达到实现多态的目的。
fig.setDisplayCallback(bind(&Circle::print, &circle));
fig.setAreaCallback(bind(&Circle::printArea, &circle));
func(fig);
return 0;
}
/*
结果
Ciecle(double)
Circle: print()
area : 314.15
~Circle()
*/
对象关系:
关系为依赖,耦合度低。
关系为继承,耦合度更高。
代码量:
绑定器需要定义一个绑定类来绑定和执行回调函数,且内部需要定义所有可能用到的函数指针类型。每次切换对象,需要重新绑定所有函数,代码过于冗余。
继承仅需要在派生类内重写虚函数,调用时通过基类指针不断变化指向实现多态,个人感觉代码更为简洁。
具体使用哪种方式根据业务需求而定。
成员函数是一个受限制的函数,mem_fn可让其不用this指针,直接绑定,功能形同普通函数。
#include
#include
#include
#include
using std::cout;
using std::endl;
using std::vector;
using std::for_each;
class Number
{
public:
Number(size_t data = 0) : _data(data){}
void print() const
{
cout << _data << " ";
}
//判断是不是偶数
bool isEven() const
{
return (0 == _data % 2);
}
//质数
bool isPrimer() const
{
if (1 == _data)
{
return false;
}
for (size_t idx = 2; idx != _data / 2; ++idx)
{
if (0 == _data % idx)
{
return false;
}
}
return true;
}
private:
size_t _data;
};
void test()
{
vector<Number> vec;
for (size_t idx = 1; idx != 30; ++idx)
{
vec.push_back(Number(idx));
}
//成员函数是一个受限制的函数
for_each(vec.begin(), vec.end(), std::bind(&Number::print, std::placeholders::_1));
/* for_each(vec.begin(), vec.end(), std::mem_fn(&Number::print)); */
/* for_each(vec.begin(), vec.end(), &Number::print); error*/
cout << endl;
vec.erase(remove_if(vec.begin(), vec.end(), std::mem_fn(&Number::isEven)), vec.end());
for_each(vec.begin(), vec.end(), std::mem_fn(&Number::print));
cout << endl;
vec.erase(remove_if(vec.begin(), vec.end(), std::mem_fn(&Number::isPrimer)), vec.end());
for_each(vec.begin(), vec.end(), std::mem_fn(&Number::print));
cout << endl;
}
int main(int argc, char** argv)
{
test();
return 0;
}
/*
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29
1 3 9 15 21 25 27
*/