类型转换与模板类型参数
- 编译器利用调用中的函数实参来确定其模板参数
- 如果一个函数uxingcan的类型使用了模板类型参数,则采用特殊初始化规则
- 编译器通常不是对实参进行类型转换,而是生成一个新的模板实例
- 顶层const无论是在形参还是实参都会被葫芦
- 其他类型转换中,能在调用中应用与函数模板的包括
- const转换:可以将一个非const的引用或指针传递给一个const的引用或指针形参
- 数组或函数指针转换:如果函数形参不是引用类型,则可以对数组和函数类型的实参引用正常的指针转换。数组实参转换为一个指向其首元素的指针,函数实参转换为一个该函数类型的指针
- 其他类型转换都不能应用于函数模板:算术转换、派生类向基类的转换、用户定义的转换
- 类型相同,长度不同的数组是不同的类型
使用相同模板参数类型的函数形参
- 一个模板类型参数可以用作多个函数形参的类型
- 由于只允许有限的几种类型转换,因此传递给这些形参的实参必须具有相同的类型
正常类型转换应用于普通函数形参
- 此参数的类型不依赖于模板参数。因此编译器会将其应用于正常的类型转换
函数模板显式实参
指定显式模板实参
- 显式模板实参在尖括号中给出,位于函数名之后
- 显式模板实参按由左到右的顺序与对应的模板实参匹配,只有尾部参数的显式模板实参才可以忽略
正常类型转换应用于显式指定的实参
- 对于用普通类型定义的函数参数,允许进行正常的类型转换
- 对于模板类型参数已经显式指定了的函数实参,也能进行正常的类型转换
尾置返回类型与类型转换
- decltype(T)T的类型
- 尾置返回类型出现在函数参数列表之后,可以使用函数的参数
template<typename It>
auto fcn(It beg, It end)->decltype(*beg)
{
return *beg;
}
进行类型转换的标准库模板类
- 所有迭代器操作都不会生成元素,值能生成元素的引用
- 类型转换模板存放在type_traits头文件上
- remove_reference模板有一个type类型成员,用于表示被引用的类型
- 组合remove_reference、decltype和位置返回可以在函数中返回元素值的拷贝
template<typename T>
auto fcn2(It beg, It end)->
typename remove_reference(decltype(*beg))::type
{
return *beg;
}
函数指针和实参推断
- 当我们用一个函数模板初始化一个函数指针或者为一个函数指针赋值时,编译器使用指针的类型来推断模板实参
templatr<typename T>int compare(const& T,const& T);
int (*pf1)(const &int,const &int) = compare;
- 当参数是一个函数模板实例的地址时,程序上下必须满足:对每个模板参数,能唯一去诶的那个其类型或值
模板实参推断和引用
从左值引用函数参数推断类型
- 当一个函数参数是模板类型参数的一个普通引用时,只能传递给它一个左值,实参可以是const的,也可以不是,如果是const的实参,那么T将被推断成const类型
- 如果一个函数参数类型是const &T,可以传递给它任何类型的实参,但函数参数本身是const类型时,T的类型推断不会是一个const类型,const已经是函数参数的一部分了
从右值引用函数参数推断类型
- 当一个函数参数是一个右值引用时,我们可以传递给他一个右值,推断出T的类型应该是右值实参的类型
引用折叠和右值引用参数
- C++语言在正常绑定外另外定义了两个例外规则
- 将一个左值传递给函数的右值引用参数,且此右值引用指向模板类型参数时,编译器推断模板类型参数为实参的左值引用类型
- 通常不能定义一个引用的引用,但是通过类型别名或通过模板类型参数的间接定义是可以的。一般情况下,引用折叠或折叠成普通的左值引用类型,除了右值引用的引用
- 如果一个 函数参数是指向模板参数类型的右值引用,则可以传递给它任何类型的实参。如果将一个左值传递个这样的参数,则函数参数将被实例化为一个普通的左值引用
编写接收右值引用的模板
- 右值引用通常用于两种情况:模板转发其实参或模板被重载
- 函数体内的赋值语句是拷贝还是引用,得看模板参数的实际类型
理解std::move()
- move获取一个绑定到左值上的右值引用
- 从一个左值static_cast是允许的
转发
- 某些函数需要将其一个或多个实参连同类型不变地转发给其他函数
template<typename F,typename T1,typename T2>
void flip1(F f,T1 t1,T2 t2)
{
f(t2,t1);
}
- 该函数一般情况下能很好执行,但是当用它来调用一个接受引用参数的函数时,会出现问题
void f(int v1,int &v2);
- f改变绑定到v2的值,但是我们通过flip1调用f,f所做的改变不会影响实参,因为flip1的t1是实参的一个拷贝
定义能保持类型信息的函数参数
- 如果一个函数参数指向模板类型参数的右值引用,它对应的实参的const属性和左值右值属性将得到保持
template<typename F,typename T1,typename T2>
void flip2(F f,T1 &&t1,T2 &&t2)
{
f(t2,t1);
}
在调用中使用std::forward保持类型信息
- move和forward都在头文件utility中
- forward必须通过显式模板实参来调用
- forward返回该显式实参的右值引用
- 使用forward传递那些定义为模板类型参数的右值引用的函数参数,通过其返回类型上的引用折叠,forward可以保持给定实参的左值\右值属性
template<typename type> flip2(type arg)
{
finalFcn(std::forward<Type>(arg));
}
template<typename F,typename T1,typename T2>
void flip2(F f,T1 &&t1,T2 &&t2)
{
f(std::forward<T2>(t2),std::forward<T1>(t1));
}