Skip to content

第四章-新手易学老兵易用

回到目录

4.1 右尖括号>的改进

使用模板时,会加上下文判断,不会识别成右移操作符

4.2 auto类型推导

  • 重新实现auto的语义
  • auto声明变量的类型必须由编译器在编译时期推导
  • auto声明的变量必须被初始化
  • auto优势
    • 简化代码,迭代器类型定义很长的时候可以用
    • 避免一些在类型声明时的错误,隐式转换
    • 一定程度上支持泛型的编程

TODO auto 与 const 去除cv语义?

4.3 decltype

  • typeid(a).name()
  • 简化代码,比如迭代器typedef decltype(vec.begin()) vectype,看起来跟auto非常类似,也类似于是一种“占位符”式的替代
  • 重用匿名类型,比如匿名结构体
  • 在模板中的作用

4.3.3 decltype推导四规则

  • 如果e是一个没有带括号的标记符表达式(id-expression)或者类成员访问表达式,那么decltype(e)就是e所命名的实体的类型。此外,如果e是一个被重载的函数,则会导致编译时错误。
  • 否则,假设e的类型是T,如果e是一个将亡值(xvalue),那么decltype(e)为T&&。
  • 否则,假设e的类型是T,如果e是一个左值,则decltype(e)为T&。
  • 否则,假设e的类型是T,则decltype(e)为T。

第一点和第三点需要注意

4.3.4 cv限制符的继承与冗余的符号

  • decltype能够表示表达式的cv限制符(易变的,不变的)的。但是如果对象的定义中有const或volatile限制符,使用decltype进行推导时,其成员不会继承const或volatile限制符
  • int i = 1; int &j = 1; decltype(j) &var2 = i; // var2有冗余的&,会被忽略

4.4 追踪返回类型

4.4.1 追踪返回类型的引入

使用

template<typename T1, typename T2>
auto sum(const T1 &a, const T2 &b)->decltype(a + b) {
    return a + b;
}
double ret = sum<int, double>(10, 2.5);

4.4.2 使用追踪返回类型的函数

  • 可以省略作用域

    class TestNameSpaceTestNameSpace {
    public:
        struct TestT {int b;};
        TestT data_;
        TestT getb();
    };
    
    // TestNameSpaceTestNameSpace::TestT TestNameSpaceTestNameSpace::getb() {
    //     return data_;
    // }
    // 可以不用写 TestNameSpaceTestNameSpace::TestT
    auto TestNameSpaceTestNameSpace::getb()->TestT {
        return data_;
    }
    

  • 模板中的一些类型推导 整个例子中没有看到一个“具体”的类型声明。

    // 同 4.4.1 例子
    template<typename T1, typename T2>
    auto sum(const T1 &a, const T2 &b)->decltype(a + b) {
        return a + b;
    }
    double ret = sum<int, double>(10, 2.5);
    

  • 简化函数的定义,提高代码的可读性,函数指针

    int (*p1)(int a);
    auto (*p2)(int a)->int;
    

  • 转发函数 用了追踪返回类型,可以实现参数和返回类型不同时的转发

4.5 基于范围的for循环

for (const auto &i : vec) {}