16.2节练习

来源:互联网 发布:苹果4s支持4g网络吗 编辑:程序博客网 时间:2024/06/05 21:57

练习16.32 在模板实参推断过程中发生了什么?

从函数实参来确定模板实参的过程被称为模板实参推断。在模板实参推断过程中,编译器使用函数调用中的实参类型在寻找模板实参,用这些模板实参生成的函数版本与给定的函数调用最为匹配。


练习16.33 指出在模板实参推断过程中允许对函数实参进行的两种类型转化。

const转换:可以将一个非const对象的引用/指针传递给一个const引用/指针形参。

数组或函数指针转换:如果函数形参不是引用类型,则可以对数组或函数类型的实参应用正常的指针转换。一个数组实参可以转换为一个指向其首元素的指针。类似的,一个函数实参可以转换为一个该函数类型的指针。


练习16.34 对下面的代码解释每个调用是否合法。如果合法,T的类型是什么?如果不合法,为什么?

template <class T> int compare(const T&, const T&);(a)compare("hi", "world");//不合法。数组大小不同,类型不匹配(b)compare("bye", "dad");//合法。compare(const char[4], const char[4]);


练习16.35 下面调用中哪些是错误的(如果有的话)?如果调用合法,T的类型是什么?如果调用不合法,问题何在?

template <typename T> T calc(T, int);template <typename T> T fcn(T, T);double d;float f;char c;(a) calc(c, 'c');//calc(char,int);(b) calc(d, f);//calc(double,int);(c) fcn(c, 'c');//fcn(char,char);(d) fcn(d, f);//非法,类型不匹配


练习16.36 进行下面的调用会发生什么?
template <typename T> f1(T, T);template <typename T1, typename T2> f2(T1, T2);int i = 0, j = 42, *p1 = &i, *p2 = &j;const int *cp1 = &i, *cp2 = &j;(a)f1(p1, p2);//f1(int*, int*);(b)f2(p1, p2);//f2(int*, int*);(c)f1(cp1, cp2);//f1(const int*, const int*);(d)f2(cp1, cp2);//f2(const int*, const int*);(e)f1(p1, cp1);//f1(int*, const int*)类型不匹配,非法(f)f2(p1, cp1);//f2(int*, const int*); 

练习16.37 标准库max函数有两个参数,它返回是实参中的较大者。此函数有一个模板类型参数。你能在调用时传递给它一个int和一个double吗?如果可以,如何做,如果不可以,为什么?

template<typename T, typename T2, typename T3>T max(T2 a, T3 b){return a < b ? b : a;}调用auto i = max< ? >max(i1, i2);
不可以,不能确定返回类型。


练习16.38 当我们调用make_shared时,必须提供一个显示模板实参。解释为什么需要显示模板实参以及它是如何使用的。

返回一个指向该实参类型的指针。


练习16.39 对16.1.1节(578页)中的原始版本的compare函数,使用一个显式模板实参,使得可以向函数传递两个字符串字面值常量。

    compare<string>("pierce", "paul");  


练习16.40 下面的函数是否合法?如果不合法,为什么?如果合法,对可以传递的实参类型有什么限制(如果有的话)?返回类型是什么?

template <typename It>  auto fcn3(It beg, It end) -> decltype(*beg + 0){    return *beg; } 
合法,返回类型是元素的拷贝,不是引用。

对可以传递的实参剋那个的限制是要求可以调用算术运算符。


练习16.41编写一个新的sum版本,它的返回类型保证足够大,足以容纳加法结果。

template <typename T1, typename T2>  long double sum(const T1 &a, const T2 &b){    return a + b;  }   

练习16.42  对下面每个调用,确定T和val的类型。

template <typename T> void g(T&& val);int i = 0;const int ci = i;(a) g(i);//T-int&, val-左值(b) g(ci);//T-const int&, val-左值(c) g(i*ci);        //T- int, val-右值

练习16.43 使用上一题定义的函数,如果我们调用g(i=ci),g的模版参数将是什么?

int&


练习16.44 使用第一题中相同的三个调用,如果g的函数参数声明为T(而不是T&&),确定T的类型。如果g的函数参数是const T&呢?

函数参数为T:

(a) int&   (b) cont int& (c) int

函数参数为const T&(实参中的const是无关的):
(a) int   (b) int  (c) int


练习16.45 给定下面的模板,如果我们对一个像42这样的字面常量调用g,解释会发生什么?如果我们对一个Int类型的变量调用g呢?

template <typename T> void g(T&& val) { vector<T> v; }

实参为42是字面值常量,T被推断为int。

而实参为int时候,T被推断为int&,使用vector<int&>将是错误的。


练习16.46 解释下面的循环,它来自13.5节(469页)中的StrVec::reallocate。

for (size_t i = 0; i != size(); ++i) {alloc.construct(dest++, std::move(*elem++));}
将容器中的元素通过指针移动到新构造的容器。move中的参数是右值。


练习16.47 编写你自己版本的反转函数,通过调用接受左值和右值引用参数的函数来测试它。

template <typename F, typename T1, typename T2>void flip(F f, T1 &&t1, T2 &&t2){f(std::forward<T2>(t2), std::forward<T1>(t1));}



0 0
原创粉丝点击