UP | HOME

Ping's Tech Notes

关于 decltype,remove_pointer ,别名和函数指针类型

Ping Zhou, 2022-11-12

C++里的 decltype 是个神奇的存在,你给它一个名字或表达式,它会返回这个名字或表达式的类型。并且这个检查是在编译时进行的,所以你给它的表达式不会真的运行,而只是用作类型推导,例如:

bool f();
decltype(f()) a;  // a is bool

这里 decltype 在编译时用 f() 推导出类型 bool(因为函数 f 返回 bool),但实际运行时并不会真的执行这个 f()

大部分时间, decltype 都能返回你想要的结果。

但是遇到别名和函数指针类型,情况就会绕一些,咱们分别讨论一下。

using II = int* ();
// This is equivalent to declaring an external function (not a pointer):
// extern int* a1();
II a1;
// This will cause compile error unless a function int* a1() is implemented.
// a1();

类型别名 II 是一个返回 int* 的函数类型(注意,不是函数指针哈)。于是用 II 声明的 a1 就是一个返回 int* 的函数。但是这里只是申明了函数 a1 而已,并没有它的实现,所以调用 a1 是会编译出错的。

using III = int* (*)();
III a2;
// decltype(a2) is int* (*)()

这里,别名 III 是一个返回 int* 的函数指针类型,然后用它声明了一个变量(函数指针) a2 。如果我们对 a2decltype ,得到的就是类型 III

既然如此,我们何不直接对 IIIdecltype 呢?答案是不行的, decltype 需要表达式或者变量/函数名,不能直接拿类型。但是我们可以这么用:

decltype(III()) a3;

III 变成 III() 表达式,意思是“产生一个 III 类型的实例”,然后这个表达式的类型送入 decltype ,就得到了 III 类型本身。

再进一步,要是我们给类型加上 remove_pointer 呢?

using IIII = std::remove_pointer<decltype(III())>::type;

里面的 decltype(III()) 就是类型 III ,即“返回 int* 的函数指针类型”,因此上面这个表达式意思就是: 对一个函数指针类型做 remove_pointer

我们知道 remove_pointer 会剥离输入类型里的指针,例如把 int* 变成 int ,但是如果输入的是函数指针的话呢?答案是它会返回函数类型(也就是去掉指针),想想也挺合理的不是?

// III is int* (*)()
// IIII is int* ()
using IIII = std::remove_pointer<decltype(III())>::type;
// So this is equivalent to a function declaration:
// int* b();
IIII b;

所以 IIII 其实就是和 II 一样的类型,一个返回 int* 的函数类型。它作用在 b 上,得到一个该类型的函数声明 b

这个话题今天就聊到这里,感谢阅读!