16.2节练习

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

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


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

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

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


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

template  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  T calc(T, int);
template  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  f1(T, T);
template  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
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("pierce", "paul");  


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

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

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


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

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

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

template  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  void g(T&& val) { vector v; }

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

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


练习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 
void flip(F f, T1 &&t1, T2 &&t2)
{
	f(std::forward(t2), std::forward(t1));
}



你可能感兴趣的:(C++primer)