类型转换
- 编译器通常不对实参进行类型转换,而是生成新的模板实例
- 将实参传递给带模板类型的函数形参时,能够自动应用的类型转换:
- 顶层const被忽略
- 可以将非const对象的引用或指针传递给const的引用或指针形参
- 如果函数参数不是引用,则可将数组或函数转成指针
- 注意:
- 算数转换/子类向父类转换/用户自定义都不能应用与函数模板
- 数组大小不同是不同类型,此时如果形参是T,则被转化为指针,数组大小不赶紧要;
如果形参是引用,如
T&
,数组不会转成指针,数组的大小也是数组类型的一部分
引用折叠
- 当一个函数参数是一个右值引用,可以传递一个右值
template <typename T> void f3(T&&);
f3(42); // T是int
- 此时传递一个左值也是可以的(虽然通常不能将右值引用绑定到左值上),
当调用
f3(i)
时(i是一个左值),编译器推断T为int& - T被推断为int&好像f3的参数是一个int&的右值引用(通常直接不能定义引用的引用),
如果我们间接创建引用的引用,这些引用形成了 折叠 :
- T& &, T& &&, T&& &会折叠成T&
- T&& &&会折叠成T&&
- 上面两个规则使得我们可以传递任意类型的实参给T&&类型的函数形参(传递左值将会化为左值引用)
std::move
template <typename T>
// 使用typename表示后面的东西是个类型
typename remove_reference<T>::type&& move(T&& t) {
// remove_reference::type脱去引用,返回类型本身
// static_cast可以显示的将左值转换为右值引用
return static_cast<typename remove_reference<T>::type&&>(t);
}
- 通过引用折叠,T&&可以和任何类型的实参匹配,可以传递左值,也可以传递右值
- move调用告诉编译器:我们有一个左值,但希望像一个右值一样处理他。 可以销毁移后源对象,也可赋予新值,但不能使用它