当前位置:嗨网首页>书籍在线阅读

29-自适应函数符和函数适配器

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

16.5.3 自适应函数符和函数适配器

表16.12列出的预定义函数符都是自适应的。实际上STL有5个相关的概念:自适应生成器(adaptable generator)、自适应一元函数(adaptable unary function)、自适应二元函数(adaptable binary function)、自适应谓词(adaptable predicate)和自适应二元谓词(adaptable binary predicate)。

使函数符成为自适应的原因是,它携带了标识参数类型和返回类型的typedef成员。这些成员分别是result_type、first_argument_type和second_argument_type,它们的作用是不言自明的。例如,plus对象的返回类型被标识为plus::result_type,这是int的typedef。

函数符自适应性的意义在于:函数适配器对象可以使用函数对象,并认为存在这些typedef成员。例如,接受一个自适应函数符参数的函数可以使用result_type成员来声明一个与函数的返回类型匹配的变量。

STL提供了使用这些工具的函数适配器类。例如,假设要将矢量gr8的每个元素都增加2.5倍,则需要使用接受一个一元函数参数的transform()版本,就像前面的例子那样:

transform(gr8.begin(), gr8.end(), out, sqrt);

multiplies()函数符可以执行乘法运行,但它是二元函数。因此需要一个函数适配器,将接受两个参数的函数符转换为接受1个参数的函数符。前面的TooBig2示例提供了一种方法,但STL使用binder1st和binder2nd类自动完成这一过程,它们将自适应二元函数转换为自适应一元函数。

来看binder1st。假设有一个自适应二元函数对象f2(),则可以创建一个binder1st对象,该对象与一个将被用作f2()的第一个参数的特定值(val)相关联:

binder1st(f2, val) f1;

这样,使用单个参数调用f1(x)时,返回的值与将val作为第一参数、将f1()的参数作为第二参数调用f2()返回的值相同。即f1(x)等价于f2(val, x),只是前者是一元函数,而不是二元函数。f2()函数被适配。同样,仅当f2()是一个自适应函数时,这才能实现。

看上去有点麻烦。然而,STL提供了函数bind1st(),以简化binder1st类的使用。可以问其提供用于构建binder1st对象的函数名称和值,它将返回一个这种类型的对象。例如,要将二元函数multiplies()转换为将参数乘以2.5的一元函数,则可以这样做:

bind1st(multiplies<double>(), 2.5)

因此,将gr8中的每个元素与2.5相乘,并显示结果的代码如下:

transform(gr8.begin(), gr8.end(), out,
        bind1st(multiplies<double>(), 2.5));

binder2nd类与此类似,只是将常数赋给第二个参数,而不是第一个参数。它有一个名为bind2nd的助手函数,该函数的工作方式类似于bind1st。

程序清单16.16将一些最近的示例合并成了一个小程序。

程序清单16.16 funadap.cpp

// funadap.cpp -- using function adapters
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <functional>
void Show(double);
const int LIM = 6;
int main()
{
    using namespace std;
    double arr1[LIM] = {28, 29, 30, 35, 38, 59};
    double arr2[LIM] = {63, 65, 69, 75, 80, 99};
    vector<double> gr8(arr1, arr1 + LIM);
    vector<double> m8(arr2, arr2 + LIM);
    cout.setf(ios_base::fixed);
    cout.precision(1);
    cout << "gr8:\t";
    for_each(gr8.begin(), gr8.end(), Show);
    cout << endl;
    cout << "m8: \t";
    for_each(m8.begin(), m8.end(), Show);
    cout << endl;
    vector<double> sum(LIM);
    transform(gr8.begin(), gr8.end(), m8.begin(), sum.begin(),
              plus<double>());
    cout << "sum:\t";
    for_each(sum.begin(), sum.end(), Show);
    cout << endl;
    vector<double> prod(LIM);
    transform(gr8.begin(), gr8.end(), prod.begin(),
              bind1st(multiplies<double>(), 2.5));
    cout << "prod:\t";
    for_each(prod.begin(), prod.end(), Show);
    cout << endl;
    return 0;
}
void Show(double v)
{
    std::cout.width(6);
    std::cout << v << ' ';
}

程序清单16.16中程序的输出如下:

gr8:   28.0   29.0   30.0    35.0    38.0    59.0
m8:    63.0   65.0   69.0    75.0    80.0    99.0
sum:   91.0   94.0   99.0   110.0   118.0   158.0
prod:  70.0   72.5   75.0    87.5    95.0   147.5

C++11提供了函数指针和函数符的替代品——lambda表达式,这将在第18章讨论。