C++ Primer学习
模板实参推断
从函数实参来确定模板实参的过程被称为模板实参推断。
模板实参推断
类型转换与模板类型参数
- const转换:可以将一个非const对象的引用(或指针)传递给一个const的引用(或指针)形参。顶层const无论是在形参中还是在实参中,都会被忽略。
- 数组或函数指针转换:函数形参不是引用类型。
- 一个模板类型参数可以用作多个函数形参的类型。
函数模板显式实参
- 显式模板实参按自左至右的顺序与对应的模板参数匹配。
尾置返回类型与类型转换
- 头文件type_traits中定义了类型转换模板。
template <typename T>
auto func(T begin,T end)->
typename remove_reference<decltype(*begin)>::type
{
//处理...
return *begin;
}
函数指针和实参推断
- 用一个函数模板初始化一个函数指针或为一个函数指针赋值时,编译器使用指针的类型来推断模板实参。
template <typename T> int compare(const T&,const T&);
//指针p所指函数中参数的类型决定T的模板实参的类型
int (*p)(const int&,const int&)=compare;
- 当参数是一个函数模板实例的地址时,程序上下文必须满足:对每个模板参数,能唯一确定其类型或值。
void func(int(*)(const string&,const string&));
void func(int(*)(const int&,const int&));
//可以通过显式模板实参来消除func调用的歧义
func(compare<int>);
模板实参推断和引用
- 编译器会应用正常的引用绑定规则;const时底层的,不是顶层的。
- T&:一个变量或一个返回引用类型的表达式。
- const T&:一个对象或一个临时量对象或是一个字面值常量值。这时T的类型推断结果不会是一个const类型。
- 两个例外规则:将一个左值传递给函数的右值引用参数,且此右值引用指向模板类型参数时,编译器推断模板参数为实参的左值引用类型;如果间接创建一个引用的引用,则这些引用形成了“折叠”。
template <typename T> void func(T&&);
int a=1;
//编译器推断T的类型为int&
func(a);
- 引用折叠只能应用于间接创建的引用的引用,如类型别名或模板参数。如果一个函数参数是指向模板参数类型的右值引用,则可以传递给它任意类型的实参。
- 右值引用通常用于两种情况:模板转发其实参或模板被重载。
理解std::move
- std::move
template <typename T>
typename remove_reference<T>::type&& move(T&& t)
{
return static_cast<typename remove_reference<T>::type&&>(t);
}
- 虽然不能隐式地将一个左值转换为右值引用,但我们可以用static_cast显式地将一个左值转换为一个右值引用。
转发
某些函数需要将其一个或多个实参连同类型不变地转发给其他函数。
- 通过将一个函数参数定义为一个指向模板类型参数的右值引用,我们可以保持其对应实参的所有类型。而使用(无论是左值还是右值)引用参数使得可以保持const属性。
- forward必须通过显式模板实参来调用,forward可以保持给定实参的左值/右值属性,定义在头文件utility中。
术语
类型转换和模板类型参数
- 使用相同模板参数类型的函数形参
- 正常类型转换应用于普通函数实参
函数模板显式实参
- 指定显式模板实参
- 正常类型转换应用于显式指定的实参
尾置返回类型与类型转换
- 进行类型转换的标准库模板类
函数指针和实参推断
模板实参推断和引用
- 从左值引用函数参数推断类型
- 从右值引用函数参数推断类型
- 引用折叠和右值引用参数
- 编写接受右值引用参数的模板函数
理解std::move
- std::move是如何定义的
- std::move是如何工作的
- 从一个左值static_cast到一个右值引用是允许的
转发
- 定义能保持类型信息的函数参数
- 在调用中使用std::forward保持类型信息