c++包装器


c++提供了多个包装器(也叫适配器)。这些对象用于给其他编程接口提供更一致或更合适的接口。

包装器function及模板的低效性

answr=ef(q);

ef是什么?它可以是函数名、函数指针、函数对象或有名称的lambda表达式。所有这些都是可调用的类型。类型如此丰富,可能导致模板的效率极低。
例:
头文件:

#ifndef G_H
#define G_H

#include<iostream>
using namespace std;
template<typename T,typename F>
T use_f(T v, F f)
{
    static int count=0;
    count++;
    cout<<"use_f count = "<<count
       <<",&count="<<&count<<endl;
    return f(v);
}

class Fp
{
private:
    double z_;
public:
    Fp(double z = 1.0):z_(z){}
    double operator ()(double p){return z_*p;}
};

class Fq
{
private:
    double z_;
public:
    Fq(double z = 1.0):z_(z){}
    double operator ()(double q){return z_+q;}
};

#endif // G_H

模板use_f使用参数f表示调用类型:
return f(v);

源文件:调用模板函数use_f()6次

#include"g.h"
#include<iostream>
using namespace std;
double dub(double x){return 2.0*x;}
double square(double x){return x*x;}

int main()
{
    double y = 1.21;
    cout<<"Function pointer dub:\n";
    cout<<" "<<use_f(y,dub)<<endl;//dub函数名称,接受个double参数并返回个double值,函数名时指针,类型为double(*)(double):一个指向这样的函数的指针,接受个double参数并返回个double值
    cout<<"Function pointer square:\n";
    cout<<" "<<use_f(y,square)<<endl;第二个参数类型也是double(*)(double),因此该调用使用的use_f()实例化与第一个调用相同。
    cout<<"Function object Fp:\n";
    cout<<" "<<use_f(y,Fp(5.0))<<endl;
    cout<<"Function object Fq:\n";
    cout<<" "<<use_f(y,Fq(5.0))<<endl;
    cout<<"Lambda expression 1:\n";
    cout<<" "<<use_f(y,[](double u) {return u*u;})<<endl;
    cout<<"Lambda expression 2:\n";
    cout<<" "<<use_f(y,[](double u){return u+u/2.0;})<<endl;
    return 0;
}

每次调用,模板参数T都被设置为类型double,模板参数F呢?每次调用时,F都接受一个double值并返回一个double值,因此在6次use_of()调用中,好像F的类型相同,因此只会实例化模板一次。下面的输出不切实际:
在这里插入图片描述
注:模板函数use_f()有个静态成员count,可根据它的地址确定模板实例化了多少次。有5个不同的地址,表明模板use_f()有5个不同的实例化。

修复问题

包装器能够重写上述程序,使其只使用use_f()的一个实例而不是5个。上面源文件中的函数指针、函数对象和lambda表达式有个相同的地方,都接受个double参数并返回一个double值。可以说调用特征标相同。调用特征标是有返回类型以及用括号括起并用头号分隔的参数类型列表定义的,所以,这6个实例的调用特征标都是double(double)。
模板function是在头文件functional中声明的,它从调用特征标的角度定义个对象。可用于包装调用特征标相同的函数指针、函数对象或lambda表达式。例如:创建个名为fdci的function对象,接受个char参数、int参数,返回double值:

function<double(char,int)>fdic;//返回double值的任何函数指针、函数对象、lambda表达式赋给它

例:修复,调用参数的调用特征标都相同:double(double)

#include"g.h"
#include<iostream>
#include<functional>
using namespace std;
double dub(double x){return 2.0*x;}
double square(double x){return x*x;}

int main()
{
    double y = 1.21;
    //创建6个包装器
    function<double(double)>ef1=dub;
    function<double(double)>ef2=square;
    function<double(double)>ef3=Fq(10.0);
    function<double(double)>ef4=Fp(10.0);
    function<double(double)>ef5=[](double u){return u*u;};
    function<double(double)>ef6=[](double u){return u+u/2.0;};
    cout<<"Function pointer dub:\n";
    cout<<" "<<use_f(y,ef1)<<endl;
    cout<<"Function pointer square:\n";
    cout<<" "<<use_f(y,ef2)<<endl;
    cout<<"Function object Fp:\n";
    cout<<" "<<use_f(y,ef3)<<endl;
    cout<<"Function object Fq:\n";
    cout<<" "<<use_f(y,ef4)<<endl;
    cout<<"Lambda expression 1:\n";
    cout<<" "<<use_f(y,ef5)<<endl;
    cout<<"Lambda expression 2:\n";
    cout<<" "<<use_f(y,ef6)<<endl;
    return 0;
}

在这里插入图片描述

其他方式

1.不用声明6个function<double(double)>对象,而只使用一个临时funxtion<double(double)>对象,将其用作函数use_f()的参数:

typedef function<double(double)>fdd;//简化类型声明
cout<<use_f(y,fdd(dub))<<endl;//创建初始化对象dub
cout<<use_f(y,fdd(square))<<endl;
...

2.use_f()的第二个实参与形参f匹配,但另一种方法是让形参f的类型与原始实参匹配。为此,可在模板use_f()的定义中,将第二个参数声明为function包装器对象,:

#include<functional>
template<typename T>
T use_f(T,v,function<T(T)> f)
{
static int count=0;
count++;
cout<<"use_f count="<<count<<",&count="<<&count<<endl;
return f(v);
}

这样函数调用:

cout<<" "<<use_f<double>(y,dub)<<endl;
...
cout<<" "<<use_f<double>(y,Fp(5.0))<<endl;
...
cout<<" "<<use_f<double>(y,[](double u){return u*u})<<endl;

参数dub、Fp(5.0)等本身类型并不是function<double(double)>,因此在use_f后面是有了来指出所需的具体化,这样,T被设置为double,而function<T(T))变成了function<double(double)>。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值