关于 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
。如果我们对 a2
用 decltype
,得到的就是类型 III
。
既然如此,我们何不直接对 III
用 decltype
呢?答案是不行的, 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
。
这个话题今天就聊到这里,感谢阅读!