auto 和 decltype

发布时间 2023-03-28 21:51:18作者: Bdathe

auto 关键字

auto 作用

auto 可以让编译器在编译期就推导出变量的类型

auto a = 10;  // 10 是 int型,可以自动推导出 a 是 int

int i = 10;
auto b = i;  // b 是 int 型

auto d = 2.0;  // d 是 double 型

auto 推导规则

代码1:

int i = 10;
auto a = i, &b = i, *c = &i;  // a 是 int,b 是 i 的引用,c 是 i 的指针,auto 就相当于 int

///\note 错误的情况
auto d = 0, f = 1.0;  // error,0 和 1.0 类型不同,对于编译器有二义性,没法推导

auto e;               // error,使用 auto 必须马上初始化,否则无法推导类型

代码2:

void func(auto value) { }  // error,auto 不能用作函数参数

class A {
    auto a = 1;         // error,在类中 auto 不能用作非静态成员变量
    static auto b = 1;  // error,这里与 auto 无关,正常 static int b = 1也不可以,类内静态变量只能类内定义,类外初始化,如果想要类内定义并初始化,但是静态常量可以类内定义并初始化
    static const auto int c = 1;  // ok
};

void func2() {
    int a[10] = { 0 };
    auto b = a;  // ok
    auto c[10] = a;         // error,auto 不能定义数组,可以定义指针
    vector < int > d;
    vector < auto > f = d;  // error,auto 无法推导出模板参数
}

从以上代码,我们可以得到如下

auto 的限制

  • auto 的使用必须马上初始化,否则无法推导出类型
  • auto 在一行定义多个变量时,各个变量的推导不能产生二义性,否则编译失败
  • auto 不能用作函数参数
  • 在类中 auto 不能用作非静态成员变量
  • auto 不能定义数组,可以定义指针
  • auto 无法推导出模板参数

涉及 const / volatile 的推导规则

目前我也不知道什么是 volatile

再看这段代码:

int i = 0;
auto * a = & i; // a 是int*
auto & b = i;   // b 是int&
auto c = b;     // c 是int,忽略了引用

const auto d = i; // d 是 const int
auto e = d;       // e 是 int

const auto& f = e; // f 是const int&
auto & g = f;      // g 是const int&

注意,下面的 cv 是指 const 和 volatile

  • 在不声明为引用或指针时,auto 会忽略等号右边的引用类型和 cv 限定
  • 在声明为引用或者指针时,auto 会保留等号右边的引用和 cv 属性

什么时候使用 auto

这里没有绝对答案,只能说一下我自己的理解,个人认为在不影响代码可读性的前提下尽可能使用 auto 是蛮好的,复杂类型就使用 auto,int、double这种就没有必要使用 auto 了吧,看下面这段代码:

auto func = [&] {
    cout << "xxx";
};  // 对于 func 你难道不使用 auto 吗,反正我是不关心 lambda 表达式究竟是什么类型。

auto asyncfunc = std::async(std::launch::async, func);
 // 对于 asyncfunc 你难道不使用 auto 吗,我是懒得写 std::futurexxx 等代码,而且我也记不住它返回的究竟是什么...

decltype 关键字

上面介绍 auto 用于推导变量类型,而 decltype 则用于推导表达式类型,这里只用于编译器分析表达式的类型,表达式实际不会进行运算,上代码:

int func() { return 0; }
decltype(func()) i;  // i 为 int 类型

int x = 0;
decltype(x) y;       // y 是 int 类型
decltype(x + y) z;   // z 是 int 类型

注意:decltype 不会像 auto 一样忽略引用和 cv 属性,decltype 会保留表达式的引用和 cv 属性

cont int &i = 1;
int a = 2;
decltype(i) b = 2;  // b 是 const int&

decltype 推导规则

对于 decltype(exp) 有

  • exp 是表达式,decltype(exp) 和 exp 类型相同
  • exp 是函数调用,decltype(exp) 和函数返回值类型相同
  • 其它情况,若 exp 是左值,decltype(exp) 是 exp 类型的左值引用
int a = 0, b = 0;
decltype(a + b) c = 0;  // c 是 int,因为 (a+b) 返回一个右值
decltype(a += b) d = c; // d 是 int&,因为 (a+=b) 返回一个左值

d = 20;
cout << "c " << c << endl;  // 输出 c 20