C++中的类型推断

C++11中引入了autodecltype,他们可以在编译期推导出出变量或表达式的类型,大幅简化了代码。

auto

auto关键字允许编译器在编译期间自动推导出变量的类型。

1
2
3
4
auto a = 10;       // a是int型​
int i = 10;​
auto b = i; // b是int型​
auto d = 2.0; // d是double型

推导规则

  • auto变量必须在声明时立即初始化
  • 当一行中声明了多个auto变量时,他们必须能够从一个共同的初始化表达式中推导出相同类型。
  • 在推导类型时,auto忽略等号右边的constvolatile(cv)属性和引用类型,除非显式地声明为引用或指针。
  • auto不能用作函数的参数
  • auto无法作为模板
  • auto在类中不能用作非静态的成员变量
  • auto不能用于定义数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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 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 e; // error,使用auto必须马上初始化

int i = 10;​
auto ai = i, &bi = i, *ci = &i; // a是int,b是int的引用,c是int的指针​

floats j = 0;
auto di = i, aj = j; //error,


auto f = 0, g = 1.0; // error,0和1.0类型不同,编译器懵了,无法推导

const int x = 10;​
auto y = x; // y是int,忽略了const属性​
auto& z = x; // z是const int&,保留了引用和const属性
}​

decltype

auto不同,decltype用于推导表达式的类型而非变量的类型。其在编译期间发挥分析表达式的类型,但是表达式本身不会进行运算

1
2
3
4
5
int func() { return 0; }​
decltype(func()) i; // i为int类型,与func()返回值类型相同​
int x = 0;​
decltype(x) y; // y是int类型,与x类型相同​
decltype(x + y) z; // z是int类型,与表达式x + y的类型相同

推导规则

  • 如果exp是一个没有圆括号的标识符表达式(id-expression),例如变量名、函数名和枚举常量名,那么decltype(exp)的类型与exp的类型相同。例如上面代码中的decltype(x)推导出的类型是int,这是因为decltype(x)decltype((x))是不同的类型
    • x是变量名时,decltype 直接获取该变量的声明类型,结果包含原始的 const 限定符、引用类型等修饰符。
    • 当表达式是 (x)(带括号)时,C++ 将其视为普通左值表达式,decltype 会推导出表达式结果类型和值类别,对命名变量使用括号会添加引用。
  • 如果exp是函数调用,则decltype(exp)的类型与函数返回值的类型相同。
  • 如果exp是左值,则decltype(exp)exp类型的左值引用
    • 注意和第一种情况的辨析
  • auto不同,decltype保留exp的cv属性和引用类型
1
2
3
4
5
6
7
int a = 0, b = 0;​
decltype(a + b) c = 0; // c是int,因为(a+b)返回一个右值​
decltype(a += b) d = a; // d是int&,因为(a+=b)返回一个左值​
d = 20; // 修改d实际上修改了a的值​

const int& ref = a;​
decltype(ref) e = 20; // e是const int&,保留了const引用属性

decltype常和auto一起配合使用。比如处理复杂的类型和模板编程

1
2
3
std::vector<int> vec = {1, 2, 3, 4, 5};​
auto it = vec.begin(); // 使用auto简化迭代器类型声明​
decltype(*it) value = *it; // 使用decltype推导迭代器指向的元素的类型

以及推导函数返回值的类型

1
2
3
4
template<typename T, typename U>​
auto add(T t, U u) -> decltype(t + u) {​
return t + u;​
}

需要注意

1
2
3
4
template<typename T, typename U>​
decltype(t + u) add(T t, U u) { // t和u尚未定义​
return t + u;​
}

这段代码在C++11上是编译不过的,因为函数的返回类型是在参数名可见之前就解析的,也就是说编译器会先解析decltype(t + u),而此时tu尚未定义,这就导致了编译器无法编译decltype(t + u),出现错误。


C++中的类型推断
https://guts.homes/2025/06/12/cpp-auto-decltype/
作者
guts
发布于
2025年6月12日
许可协议