练习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); //非法,类型不匹配
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;
}
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-右值
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));
}