极客时间-《罗剑锋的 C++ 实战笔记》文章笔记 + 个人思考

  • 语言特性
    • 06 | auto/decltype:为什么要有自动类型推导?

语言特性

06 | auto/decltype:为什么要有自动类型推导?

auto 在C++ 11 引入。

为什么说C++是静态强类型语言?
编译阶段对数据类型进行严格检查,编译阶段每个变量和表达式的类型都是确定的。

通过自动类型推导 auto 在编译阶段从编译器获取类型。

auto可以自适应表达式类型。(例如使用C++关联容器,把 map 改为 unordered_map,使用 auto 的代码不需要修改。)

auto 的自动推导只能用在初始化。(赋值初始化或列表初始化。)

代码演示:变量右边必须要有一个表达式。

auto x = 0L;// 自动推导为longauto y = &x;// 自动推导为long*auto z {&x};// 自动推导为long* auto err; // 错误,没有赋值表达式,不知道是什么类型

代码演示:类成员变量初始化不允许使用 auto

class X final{auto a = 10;// 错误,类里不能使用auto推导类型};

规则:

  1. auto 总是推导出“值类型”,绝不会是“引用”。
  2. auto 可以附加上 const、volatile、*、& 这样的类型修饰符,得到新的类型。

代码演示:上面两条规则。

autox = 10L;// auto推导为long,x是longauto& x1 = x;// auto推导为long,x1是long&auto* x2 = &x;// auto推导为long,x2是long*const auto& x3 = x;// auto推导为long,x3是const long&autox4 = &x3;// auto推导为const long*,x4是const long*

decltype 通过在 () 中 输入可用于计算类型的表达式,编译器在编译阶段获取表达式类型。
相对于 auto 只能用于初始化,decltype 应用场景更多。
代码演示:decltype 使用

int x = 0;// 整型变量decltype(x) x1;// 推导为int,x1是intdecltype(x)&x2 = x;// 推导为int,x2是int&,引用必须赋值decltype(x)*x3;// 推导为int,x3是int*decltype(&x)x4;// 推导为int*,x4是int*decltype(&x)* x5;// 推导为int*,x5是int**decltype(x2)x6 = x2;// 推导为int&,x6是int&,引用必须赋值。decltype 能够推推导出引用。

decltype 能够推推导出引用,其他方面就和 auto 一样了,也能加上 const、*、& 来修饰。

decltype 可以用在变量声明、函数参数 / 返回值、模板参数等任何类型能出现的地方。

decltype 写起来稍微麻烦一点:decltype(x)& x2 = x; 表达式写了2遍。

C++14 新增 decltype(auto)
代码演示:decltype(auto)

int x = 0;// 整型变量decltype(auto) x1 = (x);// 推导为int&,因为(expr)是引用类型。x是值类型,加上括号就变成了引用类型。decltype(auto) x2 = &x; // 推导为int*decltype(auto) x3 = x1; // 推导为int&

auto:

  1. 变量声明和初始化时使用更好,获取值类型。
  2. range-based for 使用,为了保证效率,最好使用“const auto&”或者“auto&”。
  3. C++14,推导函数返回值类型。

代码演示:range-based for 使用,为了保证效率,最好使用“const auto&”或者“auto&”。

 vector<int> v = {2,3,5,7,11};// vector顺序容器 for(const auto& i : v) {// 常引用方式访问元素,避免拷贝代价 cout << i << ",";// 常引用不会改变元素的值 } for(auto& i : v) {// 引用方式访问元素 i++;// 可以改变元素的值 cout << i << ","; }

代码演示:C++14,推导函数返回值类型。

auto get_a_set()// auto作为函数返回值的占位符{std::set<int> s = {1,2,3};return s;}

decltype:

  1. 可以用在任意场合。(泛型编程中经常用到。)
  2. 当你感觉“这里我需要一个特殊类型”的时候,选它就对了。
  3. 推导类数据成员类型。

代码演示:使用decltype可以轻松得到函数指针类型

// UNIX信号函数的原型,看着就让人晕,你能手写出函数指针吗?void (*signal(int signo, void (*func)(int)))(int)// 使用decltype可以轻松得到函数指针类型using sig_func_ptr_t = decltype(&signal) ;

代码演示:推导类数据成员类型。

class DemoClass final{public:using set_type= std::set<int>;// 集合类型别名private:set_typem_set; // 使用别名定义成员变量// 使用decltype计算表达式的类型,定义别名using iter_type = decltype(m_set.begin());iter_type m_pos; // 类型别名定义成员变量};