[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)。
阅读全文