《C++ Primer 4 Answer Book》 整理[15]——第16章 模板与泛型编程


16   模板与泛型编程

        11116.2编写一个函数模板,接受一个ostream引用和一个值,将该值写入流。用至少4种不同类型调用函数,通过写至cout、文件和stringstream来测试你的程序。

        答:#include <iostream>

                  #include<string>

                  #include<fstream>

                  #include<sstream>

                  usingnamespace std;

        

                  template<typename T1,typename T2>

                  T1&print(T1& s,T2 val)

                  {

                           s<<val;

                           returns;

                  }

 

                  intmain()

                  {

                           doubledval=0.88;

                           floatfval=-12.3;

                           stringoristr=”this is a test”,desstr;

                           ostringstreamoss(desstr);

                           ofstreamoutFile(“result.dat”);        

 

                           //写至cout

                           print(cout,-3)<<endl;

                           print(cout,dval)<<endl;

                           print(cout,fval)<<endl;

                           print(cout,oristr)<<endl;

                           

                           //写至文件

                           print(outFile,-3)<<endl;

                           print(outFile,dval)<<endl;

                           print(outFile,fval)<<endl;

                           print(outFile,oristr)<<endl;

                           outFile.close();

 

                           //写至stringstream

                           print(oss,-3)<<endl;

                           print(oss,dval)<<endl;

                           print(oss,fval)<<endl;

                           print(oss,oristr)<<endl;

                           

                           //stringstream中的字符输出到cout以进行验证

                           cout<<oss.str()<<endl;

                           return0;

                  }

                           

        11216.3当调用两个string对象的compare时,传递用字符串字面值初始化的两个string对象,如果编写以下代码会发生什么?

        compare(“hi”,”world”);

        答:该代码会出现编译错误。因为根据第一个实参”hi”可将模板形参T推断为char[3],而根据第二个实参”world”可将模板形参推断为char[6]T被推断为两个不同的类型,所以编译器无法使用函数模板compare进行适当的实例化以满足需求。

                  

        11316.7解释下面每个函数模板的定义并指出是否有非法的。

        a)template<class T,U,  typename V> voidf1(T,U,V);

                  非法,模板类型形参前必须带有关键字typenameclass,模板非类型形参前必须带有类型名,而这里U作为f1的形参类型使用,应该是一个类型形参,所以应在模板形参表中U的前面加上class或者typename

        b)template<classT>T f2(int &T);

                  非法,如果单纯从函数模板定义的语法来看,该定义是合法的。但是,模板形参T没有作为类型在模板函数的形参表中出现,因此将无法对其进行模板实参推断,所以,该模板函数的定义是错误的;

        c)inlinetemplate<class T> T foo(T,unsigned int*);

                  非法,inline不能放在关键字template之前,应放在模板形参表之后,函数返回类型之前;

        d)template<classT> f4(T,T);

                  在标准C++中非法;没有指定函数f4的返回类型。

        e)typedefchar Ctype;

         template <typename Ctype> Ctypef5(Ctype a);

                  合法。定义了一个模板函数f5,该函数的返回类型与形参类型相同,均可绑定到任意类型。

        

        11416.10声明为typename的类型形参与声明为class的类型形参有区别吗?区别在哪里?

        答:在标准C++中,声明为typename的类型形参与声明为class的类型形参没有区别。但是,标准C++之前的系统有可能只支持使用关键字class来声明模板类型形参。

        

        11516.11何时必须使用typename

        答:如果要在函数模板内部使用在类中定义的类型成员,必须在该成员名前加上关键字typename,以告知编译器将该成员当作类型。

        

        11616.15编写可以确定数组长度的函数模板

        答:可以使用非类型模板形参编写如下函数模板

                  template<typename T,std::size_t N>

                  std::size_tsize(T (&arr)[N])

                  {

                           returnN;

                  }

        

        11716.20在模板实参推断期间发生什么?

        答:根据函数调用中给出的实参确定模板实参的类型和值;

 

        11816.21指出对模板实参推断中涉及的函数实参允许的类型转换。

        答:const转换:接受const引用或const指针的函数可以分别用非const对象的引用或指针来调用,无需产生新的实例化。如果函数接受非引用类型,形参类型和实参都忽略const,即无论传递const或非const对象给接受非引用类型的函数,都使用相同的实例化。

                  数组或函数到指针的转换:如果模板形参不是引用类型,则对数组或函数类型的实参应用常规指针转换。数组实参将当做指向其第一个元素的指针,函数实参当做指向函数类型的指针。

 

        11916.22对于下面的模板:

                  template<class Type>

                  Typccalc(const Type* array,int size);

                  

                  template<class Type>

                  Typefcn(Type p1,Type p2);

                  下面这些调用有错吗?

                  doubledobj; float fobj; char cobj;

                  intai[5]={22,13,4,12,24};

                  a)calc(cobj,’c’);

                           实参cobj的类型为char,但是,不能使用函数模板calc产生第一个形参为非指针类型的函数实例;

                  b)calc(dobj,fobj);

                           实参dobj的类型为double,但是,不能使用函数模板calc产生第一个形参为非指针类型的函数实例;

                  c)fcn(ai,cobj);

                           函数模板fcn中两个形参的类型必须是相同的,而函数调用fcn(ai,cobj)中给出的两个实参类型不同,不能进行实例化。

        

        12016.23标准库函数max接受单个类型形参,可以传递intdouble对象调用max吗?

        答:可以,只需使用强制类型转换将其中一个对象转换为intdouble类型,使其与另一对象类型相同即可。

        

        12116.24对于具有单个模板类型形参的compare版本,传给它的实参必须完全匹配,如果想要用兼容类型如intshort调用该函数,可以使用显式模板实参指定intshort作为形参类型。编写程序使用具有一个模板形参的compare版本,使用允许你传递intshort类型实参的显式模板实参调用compare

        答:#include <iostream>

                  usingnamespace std;

                  template<typename T>

                  intcompare(const T& v1,const T& v2)

                  {

                           if(va<v2)return -1;

                           if(v2<v1)return 1;

                           return0;

                  }

                  

                  intmain()

                  {

                           shortsval =123;

                           intival=1024;

                           cout<<compare(static_cast<int>(sval),ival)<<endl;

                           cout<<compare(sval,static_cast<short>(ival))<<endl;

                           cout<<compare<short>(eval,ival)<<endl;

                           cout<<compare<int>(sval,ival)<,endl;

                           return0;

                  }

        

        12216.25使用显式模板实参,使得可以传递两个字符串字面值调用compare

        答:只需按如下方式使用显式模板实参:

                  compare<std::string>(“mary”,”mac”);     

                  亦可采用如下强制类型转换方式:

                  compare(static_cast<std::string>(“mary”),static_cast<std::string>(“mac”))

                   compare(std::string(“mary”),std::string(“mac”))

 

        

        12316.26对于下面的sum模板定义:

                  template<classT1, class T2, class T3>T1 sum(T2,T3);

                  解释下面的每个调用。如果有,指出哪些是错误的。

                  doubledobj1,dobj2; float fobj1,fobj2; char cobj1,cobj2;

                  a)sum(dobj1,dobj2);

                           错位,没有为模板类型形参T1指定相应的类型实参;

                  b)sum<double,double,double>(fobj1,fobj2);

                           正确,编译器将根据显式模板实参为该调用产生函数实例double sum(double,double),并将两个函数实参由float类型转换为double类型来调用该实例;

                  c)sum<int>(cobj1,cobj2);

                           正确,编译器将根据显式模板实参及函数实参为该调用产生函数实例int sum(char,char).

                  d)sum<double,, double>(fobj2,dobj2);

                           错位,只有最右边形参的显式模板实参可以省略,不能用代替被省略的显式模板实参。

        

        12416.36每个带标号的语句,会导致实例化吗?

                  template<class T> class Stack{};

                  voidf1(Stack<char>);  //a)

                  classExercise{

                           Stack<double>&rsd;   //b)

                           Stack<int>s1;    //c)

                  };

                  intmain(){

                           Stack<char>*sc;   //d)

                           f1(*sc);   //e)

                           intiObj=sizeof(Stack<string>);  //f)

                  }

        答:a)不会导致实例化,函数声明不会导致实例化;

                  b)不会导致实例化,定义引用不会导致实例化;

                  c)会导致实例化,在创建Exercise对象时会实例化Stack<int>类及其默认构造函数(严格来说这样的实例化不是由语句c)直接导致的,而是由定义Exercise对象的语句导致的;

                  d)不会导致实例化,定义指针不会导致实例化;

                  e)会导致实例化,调用函数f1时需创建形参对象,此时导致实例化Stack<char>类及其默认构造函数。注意,题目此处有误,指针sc尚未赋值就使用了。

                  f)会导致实例化,sizeof操作需要使用具体类,此时导致实例化Stack<string>.

        

        12516.37下面哪些模板实例化是有效的?解释为什么实例化无效。

                  template<class T,int size> class Array{…};

                  template<inti,int w>class Screen{…}

                  a)constint i=40,w=80; Screen<i,w+32> sObj;

                  b)constint arr_size =1024; Array<string , arr_size> a1;

                  c)unsignedint asize=255; Array<int,asize> a2;

                  d)constdouble db=3.1222; Array<double,db> a3;

                  答:有效的模板实例化包括a)b);

                           c)之所以无效,是因为非类型模板实参必须是编译时常量表达式,不能用变量asize作模板实参;

                           d)之所以无效,是因为dbdouble型常量,而该模板实例化所需的非类型模板实参为int型常量。

        

        12616.42编写一个输入操作符,读入一个istream对象并将读取的值放入一个Queue对象中。

        答:template<class Type>

                  istream&operator>> (istream &is,Queue<Type> &q)

                  {

                           Typeval;

                           while(is>>val)

                                    q.push(val);

                           returnis;

                  }

        

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值