auto 和 decltype

auto

使用了 auto 关键字以后,编译器会在编译期间自动推导出变量的类型,这样我们就不用手动指明变量的数据类型了。auto 仅仅是一个占位符,在编译器期间它会被真正的类型所替代。

注意点

  1. auto 变量必须在定义时初始化,因为编译器需要根据初始化表达式来推导类型
  2. auto 不能在函数的参数中使用,因为 auto 后面的变量需要初始化,当时函数的参数还只是声明(哪怕你是给这个函数参数填上默认参数也不行)
  3. auto 其实在 C++11 不能用于推断函数的返回值,当时 C++14 支持了。在 C++11 不支持推断函数的返回值的情况下,利用 decltype 能解决这个问题
  4. 当 auto 用于数组或函数指针时,数组会退化为指针类型,函数会退化为函数指针类型
  5. 推导规则遵循 C++ 类型规则,如:如果表达式是按值传递的,那么 auto 推导出的类型是值类型,而不是引用类型
  6. 当 = 右边的表达式是一个引用类型时,auto 会把引用抛弃,直接推导出它的原始类型
  7. auto 关键字不能定义数组
  8. auto 只能用于类的静态成员,不能用于类的非静态成员(普通成员)
  9. 一旦类型被推导出来,变量的类型就固定了,不会因为初始化表达式的类型发生变化而改变

最后一点可能不容易理解,举例说明:

1
auto x = 42;  // x 的类型被推导为 int

在这个例子中,x 的类型被推导为 int,因为 42 是一个整数字面值(int 类型)。即使你在以后改变 x 的值为不同类型的数据,x 的类型也不会改变,它仍然是 int。

1
x = 3.14;  // 虽然你尝试赋值一个 double 类型,但 x 仍然是 int

在这里,x 已经被推导为 int 类型,因此赋值时,3.14 会被截断为整数 3,因为 x 是 int 类型。

auto 与 const 结合

  • 当类型不为引用时,auto 的推导结果将不保留表达式的 const 属性
  • 当类型为引用时,auto 的推导结果将保留表达式的 const 属性

decltype

decltype 和 auto 功能相同,但 auto 有些无法做到的 decltype 可以完成。

1
decltype(exp) varname = value;

auto 会根据 value 推断类型,当时decltype 根据 exp 表达式(变量、字面量、带有运算符的表达式)推导出变量的类型,跟 = 右边的 value 没有关系。

当程序员使用 decltype(exp) 获取类型时,编译器将根据以下三条规则得出结果:

  • 如果 exp 是一个不被括号( )包围的表达式,或者是一个类成员访问表达式,或者是一个单独的变量,那么decltype(exp) 的类型就和 exp 一致,这是最普遍最常见的情况
  • 如果 exp 是函数调用,那么 decltype(exp) 的类型就和函数返回值的类型一致
  • 如果 exp 是一个左值,或者被括号( )包围,那么 decltype(exp) 的类型就是 exp 的引用;假设 exp 的类型为 T,那么 decltype(exp) 的类型就是 T&

auto和decltype的区别

类型推导的时机和方式

auto:

  • auto 在变量声明和初始化时,根据初始化表达式推导变量的类型。
  • auto 只能用于变量声明,并且必须在声明时进行初始化。
  • 如果表达式是一个引用或 const,auto 会去掉引用性和 const 修饰符(除非明确指定 auto& 或 const auto&)。
1
2
3
4
5
cppCopy codeint x = 10;
const int& ref = x;

auto a = ref; // a 的类型是 int,引用和 const 被去掉
auto& b = ref; // b 的类型是 const int&,保持引用和 const

decltype:

  • decltype 在编译时根据表达式的形式推导类型,表达式本身并不一定需要被执行。
  • decltype 不要求表达式初始化,并且可以用于任何有效的表达式。
  • decltype 会保留表达式的原始类型,包括引用性和 const 修饰符。
1
2
3
4
5
cppCopy codeint x = 10;
const int& ref = x;

decltype(x) a; // a 的类型是 int
decltype(ref) b = x; // b 的类型是 const int&

用途

auto:

  • 用于推导变量的类型,简化代码。
  • 经常用于遍历容器、返回值复杂的函数调用、lambda 表达式等。
1
2
cppCopy codestd::vector<int> vec = {1, 2, 3};
auto it = vec.begin(); // it 的类型是 std::vector<int>::iterator

decltype:

  • 用于获取表达式的类型,而不是直接声明变量。它可以用于推导函数的返回类型,或者声明与另一个变量具有相同类型的新变量。
  • decltype 常用于模板编程、函数返回类型推导,以及需要精确获取类型的场合。
1
2
cppCopy codeint x = 10;
decltype(x) y = 20; // y 的类型是 int

类型推到的结果

auto:

  • auto 的推导结果通常是值类型,除非显式使用引用或指针。
  • 对于引用类型,auto 会去掉引用和 const 修饰符(除非使用 auto& 或 const auto&)。
1
2
cppCopy codeconst int x = 10;
auto y = x; // y 的类型是 int,不是 const int

decltype:

  • decltype 会精确获取表达式的类型,包括引用性和 const 性质。
  • 可以区分左值引用、右值引用等不同情况。
1
2
3
cppCopy codeint x = 10;
decltype(x) a; // a 是 int 类型
decltype((x)) b = x; // b 是 int& 类型,因为 (x) 是一个左值表达式