本篇笔记包含 Term 01~06。
Term 01:理解模板型别推导
C++ 中的类型推导机制应用于模板、auto
和 decaltype
template<typename T>
void f(ParamType param); // ParamType 可以是 T/T*/T& 等
f(expr) // call the function
- ParamType 是引用或者指针,但不是万能引用
template<typename T>
void f(T& param);
int x = 1;
const int cx = x;
f(x); // T: int, param: int&
f(cx); // T: const int, param: const int&
- ParamType 是万能引用,要区分实参是左值还是右值
template<typename T>
void f(T&& param);
int x = 1;
const int cx = x;
f(x); // T: int, param: int&
f(cx); // T: const int, param: const int&
f(27); // T: int, param: int&&
- ParamType 是传值方式
template<typename T>
void f(T param);
int x = 1;
const int cx = x;
f(x); // T: int, param: int
f(cx); // T: const int, param: int
- 数组实参和函数实参可以从引用退化为指针
template<typename T>
void f1(T param);
template<typename T>
void f2(T& param);
// void myFunc(int param[]); 完全等价于 void myFunc(int *param);
const char name[] = "J. P. Briggs"; // name 的类型是 const char[13]
const char * ptrToName = name; // ptrToName 的类型是 const char *
f1(name); // T: const char *
f2(name); // T: const char(&)[13]
Term 02:理解 auto 型别推导
auto 型别推导和 Term 1 中的模板基本一致,只需要注意两个特殊情况:
- 统⼀初始化
auto x1={27}; // 类型是 std::initializer_list<int>,值是{27}
auto x2{27}; // 类型是 std::initializer_list<int>,值是{27}
- auto 用于函数返回值或者 lambda 形参时,实际还是调用的模板推导机制
Term 03:理解 decaltype
通常情况 decaltype 是符合直觉的,注意两个特殊情形:
- 用于函数返回值
template<typename Container, typename Index> // 传入容器(支持 [] 运算符)和下标,返回元素引用类型
decltype(auto) authAndAccess(Container&& c, Index i){
authenticateUser();
return std::forward<Container>(c)[i]; // 用到了 std::forward 实现完美转发参数
}
- 左值表达式
int x = 0;
decltype((x)); // 推导为 int&
Term 04:掌握查看型别推导结果的方法
- IDE
- 编译器错误信息
template <typename T> // 只对TD进⾏声明
class TD;
TD<decltype(x)> xType; // 引出错误消息,类似于,error: aggregate 'TD<int> xType' has incomplete type and cannot be defined
- 使用
std::type_info::name
或者 Boost.TypeIndex - 以上方法都不完全可靠
Term 05:优先选用 auto,而非显式型别声明
尽量使用 auto
的优点:
- 保证初始化
- 用来表示只有编译器才掌握的型别
- 避免初始化赋值时隐式类型转换
Term 06:当 auto 推导的型别不符合开发者本意时,使用显式类型转换
假设我们在使用一个代理类设计的类,或者需要显式转换类型,使用如下代码写法是更清晰明了的:
auto index = static_cast<int>(d*c.size()); // c.size() 返回 float 类型的值
auto priority = static_cast<bool>(features[3]); // features 是std::vector<bool> 类型,features[3] 返回 std::vector<bool>::reference 类型