9

基本上,我想知道为什么编译器拒绝ptr2声明:

int main() {
    // this one works
    decltype(void())* ptr1;

    // this one does not
    decltype(void{})* ptr2;
}

如果您认为这是一个函数指针,请查看此代码:ptr1

#include <iostream>
using namespace std;

template <class T>
void f(T t) {
    cout << __PRETTY_FUNCTION__ << endl;
}

int main() {
    decltype(void())* ptr;
    f(ptr);
}

输出是void f(T) [with T = void*]

4

1 回答 1

11

[expr.type.conv]

2 表达式T(),其中是非数组完整对象类型或(可能是cv限定的)类型T简单类型说明符或类型名称说明,创建指定类型的纯右值,其值是由 value-初始化 (8.5) 类型的对象;没有对该案例进行初始化。[...]voidTvoid()

NBvoid 一个简单类型说明符

3 类似地,一个simple-type-specifiertypename-specifier后跟一个braced-init-list 使用指定的braced -init-list创建一个指定类型 direct-list-initialized (8.5.4) 的临时对象,并且它的value 是作为prvalue的临时对象。

感谢Keith Thompson指出在 /3 中创建了一个临时对象,而在 /2 中创建了一个

当我们看一下 [basic.types]/5

不完全定义的对象类型和void类型是不完整的类型(3.9.1)。对象不应被定义为具有不完整的类型。

现在很明显这void{}是不允许的,因为它会创建一个(临时)对象。void()然而,“仅”创造了一个(pr)价值。我认为这两种情况的实现(行为)没有区别,但不同的语言规则适用于它们。这些规则之一禁止创建 type 的对象void,因此会出现错误。


广告decltype(void())decltype(e)接受一个表达式e。在 [dcl.type.simple]/4 中,适用的定义decltype(e)为:

否则,decltype(e)e

(因为void()产生一个纯右值而不是一个id-expression)。

因此,decltype(void())产量void

于 2013-09-22T21:52:37.273 回答