本篇笔记包含 Term 01~06。

Term 01:理解模板型别推导

C++ 中的类型推导机制应用于模板、autodecaltype

template<typename T>
void f(ParamType param);    // ParamType 可以是  T/T*/T& 等
f(expr) // call the function
  1. 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&
  1. 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&&
  1. 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
  1. 数组实参和函数实参可以从引用退化为指针
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 中的模板基本一致,只需要注意两个特殊情况:

  1. 统⼀初始化
auto x1={27};  // 类型是 std::initializer_list<int>,值是{27}
auto x2{27}; // 类型是 std::initializer_list<int>,值是{27}
  1. auto 用于函数返回值或者 lambda 形参时,实际还是调用的模板推导机制

Term 03:理解 decaltype

通常情况 decaltype 是符合直觉的,注意两个特殊情形:

  1. 用于函数返回值
template<typename Container, typename Index> // 传入容器(支持 [] 运算符)和下标,返回元素引用类型
decltype(auto) authAndAccess(Container&& c, Index i){
    authenticateUser();
    return std::forward<Container>(c)[i];   // 用到了 std::forward 实现完美转发参数
}
  1. 左值表达式
int x = 0;
decltype((x));  // 推导为 int&

Term 04:掌握查看型别推导结果的方法

  1. IDE
  2. 编译器错误信息
template <typename T> // 只对TD进⾏声明
class TD;
TD<decltype(x)> xType; // 引出错误消息,类似于,error: aggregate 'TD<int> xType' has incomplete type and cannot be defined
  1. 使用 std::type_info::name 或者 Boost.TypeIndex
  2. 以上方法都不完全可靠

Term 05:优先选用 auto,而非显式型别声明

尽量使用 auto 的优点:

  1. 保证初始化
  2. 用来表示只有编译器才掌握的型别
  3. 避免初始化赋值时隐式类型转换

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 类型