[db:标题]
摘要:类型! 在最经典的 C++ 代码中,我们使用类似 类型名 变量名 = 表达式; 的形式声明并初始化变量,例如 int x = 1; int y = x; 在上面代码中,我们知道 y 理应与 x 的类型相同
类型!
在最经典的 C++ 代码中,我们使用类似 类型名 变量名 = 表达式; 的形式声明并初始化变量,例如
int x = 1;
int y = x;
在上面代码中,我们知道 y 理应与 x 的类型相同,但是在上面代码中,如果我们后来把 x 的类型修改为 int64_t,而忘记对应地修改 y 的类型,则可能导致灾难性的后果。对此,我们最简单的做法是使用类型别名。在 C++ 中,可以使用 using 声明类型别名:
using my_int = int;
my_int x = 1;
my_int y = x;
我们也可以使用 decltype 说明符,这是在 C++11 中添加的新关键字:
int x = 1;
decltype(x) y = x;
decltype 关键字接受一个表达式,得到该表达式的类型。与 sizeof 类似,decltype 的操作数仅作为类型推导使用,并不会在运行时真正被求值。
验证 `decltype` 不会进行求值
考虑下面代码:
#include <cstdio>
int func() {
std::puts("called!");
return 0;
}
int main() {
decltype(func()) a = 1;
return 0;
}
执行后无输出,说明 decltype 的操作数不会在运行时进行求值。
`decltype` 可以保留 `void`、指针、值类型和类型限定符
查看类型推导结果
我们可以使用声明但未定义的模板函数来查看类型推导结果:
template<typename T>
void func();
该函数会阻止程序正确链接,链接器会按顺序汇报所缺失的函数特化,根据其报错信息即可得到 T 的类型。
考虑如下代码:
#include <utility>
template<typename T>
void func();
void void_func();
int main() {
int y;
int &y2 = y;
int *y3;
const int * volatile *y4;
func<decltype(y)>();
func<decltype(std::move(y))>();
func<decltype(y2)>();
func<decltype(y3)>();
func<decltype(y4)>();
return 0;
}
链接时,你会得到类似于如下的报错信息:
a.cpp:(.text+0x16): undefined reference to `void func<int>()'
a.cpp:(.text+0x1b): undefined reference to `void func<int&&>()'
a.cpp:(.text+0x20): undefined reference to `void func<int&>()'
a.cpp:(.text+0x25): undefined reference to `void func<int*>()'
a.cpp:(.text+0x2a): undefined reference to `void func<int const* volatile*>()'
a.cpp:(.text+0x2f): undefined reference to `void func<void>()'
collect2: error: ld returned 1 exit status
这说明,decltype 推导可以正确保留 void、指针、引用和类型限定符(const 和 volatile)。
