10.3.4 Binding Arguments
10.3.4 Binding Arguments
对于一下函数:
bool check_size(const string &s, string::size_type sz);因为函数参数除了容器元素类型,还有一个长度参数,不能将其用作find_if 的predicate。
The Library bind Function
[!quote]
The bind function can be thought of as a general-purpose function adaptor. It takes a callable object and generates a new callable that "adapts" the parameter list of the original object.
调用形式:
auto newCallable = bind(callable, arg_list);| 名称 | 说明 |
|---|---|
| newCallable | 生成的新的可调用对象,调用newCallable 时,它会调用原callable,并传递参数给原callable |
| callable | 原可调用对象 |
| arg_list | 新的可调用对象的参数列表,可以使用_n 来代指 newCallable 中的参数,_1对应newCallable 中的第一个参数,_2 对应第二个,以此类推 |
Binding the sz Parameter of Check_size
使用bind()生成一个可调用对象,它接收sz 参数并传递给 chek_size()
实现:
#include <functional>
bool check_size(const string &s, string::size_type sz)
{
return s.size() >= sz;
}
int main(int argc, char **argv)
{
auto check6 = bind(check_size, std::placeholders::_1, 6);
string s0 = {"plcaeholders"};
string s1 = {"value"};
cout << check6(s0) << " " << check6(s1) << endl;
return 0;
}| 行号 | 功能 | 说明 |
|---|---|---|
| 1 | bind 的头文件 | |
| 2-5 | check_size()的定义 | |
| 9 | 定义check6,判断字符串的长度是否大于等于6 | _1 表示check_size的第一个参数,占位符定义在命名空间std::placeholders中;传递给check_size 的第二个参数sz 值为6 |
| 12 | 测试 |
结果:
1 0注
newCallable 传递给 它所bind 的callable 的参数数量 和 类型需要保持一致,即时原callable 带有默认参数,在newcallable 中也要指定。
对带有默认实参的check_size 只使用一个placeholder
bool check_size(const string &s, string::size_type sz = 3);
auto check6 = bind(check_size, std::placeholders::_1);报错:
In template: static assertion failed due to requirement 'sizeof...(_BoundArgs) == sizeof...(_Args)': Wrong number of arguments for function在find_if 中使用bind
void biggies(vector<string> &words, vector<string>::size_type sz)
{
auto wc = find_if(words.begin(), words.end(),
bind(check_size, std::placeholders::_1, sz));
//...
}check_size 的第一个参数仍然要是容器元素类型,额外的size_type 参数通过由bind 生成的可调用对象进行传递。
Using placeholders Names
由于placeholders 定义在std::placeholders 中,如果函数具有多个参数那么写起来、看起来都很麻烦。通过提前声明名称,可以直接使用_n 的形式,而无需提供完整的名称定义路径。
using std::placeholders::_1;
using namespace std::placeholders;| 行号 | 功能 | 说明 |
|---|---|---|
| 1 | 声明_1 | 可以直接使用_1,但是对于其他placeholders 仍需完整的名称定义路径 |
| 2 | 声明placeholders下的所有名称 |
Arguments to bind
newCallable 和 callable 的 arguments 之间的对应关系
实现:
void f(bool b, char c, int d, string s)
{
cout << b << " " << c << " " << d << " " << s << endl;
}
int main(int argc, char **argv)
{
auto g = bind(f, false, _2, argc, _1);
g("hello", 'm');
return 0;
}bind 中的参数 与 f中的参数的对应关系:
false <-> b
_2 : g的第二个参数 <-> c
argc <-> d
_1: g的第一个参数 <-> s
效果:
0 m 1 helloUsing to bind to Reorder Parameters
实现:
bool isShorter(const string &s1, const string &s2)
{
return s1.size() < s2.size();
}
int main(int argc, char **argv)
{
vector<string> v = {"abolish", "abortion", "about", "absorb", "abundant"};
//sort(v.begin(), v.end(), isShorter);
sort(v.begin(), v.end(), bind(isShorter, _2, _1));
for(auto s : v)
cout << s << " ";
cout << endl;
return 0;
}效果:
isShorter 排序后的结果:
about absorb abolish abortion abundant
使用bind 调换参数的位置后的结果:
abortion abundant abolish absorb about通过bind 改变了传递的参数的位置,原本按照字符串长度从小到大排序的 变成了 从大到小排序
Binding Reference Parameters
[!quote]
By default, the arguments to bind that are not placeholders are copied into the callable object that bind returns.
对于不能进行copy 的参数,如 ostream,需要额外的处理。
有一个现成的函数print,在for_each()中使用print 进行打印:
实现:
ostream& print(ostream &os, const string &s, char c)
{
os << s << c;
return os;
}
int main(int argc, char **argv)
{
vector<string> v = {"abolish", "abortion", "about", "absorb", "abundant"};
for_each(v.begin(), v.end(),
//bind(print, cout, _1, ' '));
bind(print, ref(cout), _1, ' '));
return 0;
}效果:
abolish abortion about absorb abundant直接使用bind 会报错:
error: no matching function for call to
'std::tuple<std::basic_ostream<char, std::char_traits<char> >,
std::_Placeholder<1>,
char>::tuple(std::basic_ostream<char>&,
const std::_Placeholder<1>&, char)'需要使用ref() 生成一个 contains the given reference 本身可拷贝的对象。
还有一个cref() 生成一个 holds a reference to const。
bind 对于not placeholders 就只能copy,通过ref、cref 进行包装,由他们保存不可拷贝的参数对象的reference。