16.32 在模板实参推断过程中,编译器使用函数调用中的实参类型推断模板实参,用这些模板实参生成的函数版本与给定的函数调用最为匹配。
16.33 两种转换包括:const转换,可以将一个非const对象的引用(或指针)传递给一个const的引用(或指针)形参;数组或函数指针转换:函数形参不是引用类型,则可对数组或函数类型的实参应用正常的指针转换。
16.34 都不合法,函数形参是引用类型,数组或函数无法转换为指针。
16.35 (a)合法,T为char; (b)合法,T为double; (c)合法,T为char; (d)非法
16.36 (a)T为int*; (b)T1为int*, T2为int*; (d)T为const int*; (e)非法;(f)T1为int*, T2为const int*。
16.37 可以,需要显式指定实参,比如max<double>。
16.38 使用make_shared时,存在参数与维护的对象类型不直接相关,编译器无法从参数推断模板实参,这时就要显式指定模板实参。
16.39 compare<string>("s1", "s2");
16.40 合法,限制是:元素类型必须支持+运算;返回类型:(*beg+0)是右值,返回类型被推断为元素类型的常量引用。
16.41
template <typename T1, typename T2>
auto sum(T1 a, T2 b) -> decltype(a + b)
{
return a + b;
}
16.42 template<typename T> void g(T&& val);
int i = 0; const int ci = i;
(a) g(i); //T: int &; val: int &; (b) g(ci); //T:const int &; val: const int &; (c) g(i * ci); //T: int; val: int &&
16.43 i = ci; 返回的是左值i,所以与上题(a)情况一致。
16.44 template<typename T> void g(T val);
int i = 0; const int ci = i;
(a) g(i); //T: int; val: int; (b) g(ci); //T:int; val: int; (c) g(i * ci); //T:int; val: int
template<typename T> void g(const T &val);
int i = 0; const int ci = i;
(a) g(i); //T: int; val: const int &; (b) g(ci); //T:int; val: const int&; (c) g(i * ci); //T:int; val: const int&
16.45 当调用g(42),T为int,v为vector<int>;当调用g(i),T为int &,v为vector<int&>类型,但vector需要维护指向其元素类型的指针,元素类型为int&,但不存在指向引用的指针,因此无法定义vector<int&> v。
16.46 每次循环中,construct在新内存空间创建对象,std::move将一个左值转换为右值引用,construct调用string的移动构造函数将数据从旧空间移动到新内存空间中。
16.47
#include <iostream>
using namespace std;
void f(int v1, int &v2)
{
cout << v1 << " " << ++v2 << endl;
}
template <typename F, typename T1, typename T2>
void flip(F f, T1 &&t1, T2 &&t2)
{
f(std::forward<T2>(t2), std::forward<T1>(t1));
}
int main()
{
int i = 42;
flip(f, i, 40);
cout << "i = " << i << endl;
return 0;
}