5

由于int()int{}是值等于的常量0表达式,我认为它们是等价且可互换的,因此编译器必须平等对待它们。例如,

 int a[0];      //error: zero-sized array not allowed in ISO C++
 int b[int()];  //error: zero-sized array not allowed in ISO C++
 int c[int{}];  //error: zero-sized array not allowed in ISO C++

但似乎在某些极端情况下它们不可互换。

  • 初始化指针时:

    int *p = 0;     //ok
    int *q = int(); //error - by clang only
    int *r = int{}; //error - by gcc and clang both
    

    请参阅GCCClang消息。我怀疑这是两个编译器中的一个错误,因为我希望它们在这种情况下可以互换,但我很高兴被证明是错误的。:-)

  • 传递给类模板时:

    template<int N> struct X{};
    
    X<0>      x1; //ok
    X<int{}>  x2; //ok (same as X<0>)
    X<int()>  x3; //error  
    

    请参阅GCCClang消息。

    我发现语法X<int()>非常熟悉,因为我以前见过(并且可能使用过)类似的语法,例如在 中std::function<int()>,模板参数int()应该是函数类型 (而不是0),不带参数并返回int。但是我想知道规范中在这种情况下所说的部分int()将被视为函数类型并且不等同于int{}which is always 0

4

1 回答 1

5

表达式int()int{}都是求值为零的整数类型的常量表达式纯右值,因此0在需要求值为零的整数类型的整型常量表达式纯右值的任何上下文中都可以与文字互换。

两个表达式都满足5.19 常量表达式 [expr.const]中指定的常量表达式的要求。

关于X<int()>,标准规定int()在这种情况下不被解释为表达式:

14.3 模板参数 [temp.arg]

template-argument中, type-id表达式之间的歧义被解析为type-id,而不管相应template-parameter的形式如何。

关于指针转换:

4.10 指针转换 [conv.ptr]

空指针常量是整数类型的整数常量表达式 (5.19) 纯右值,其计算结果为零或类型的纯右值std::nullptr_t

基于以上段落,int()int{}都是空指针常量表达式。这指向一个(非常小的)编译器错误,尽管有一个打开的缺陷报告(903)可能导致本段更改:

CWG 有一个强烈的共识,即只有文字 0 应被视为空指针常量,而不是当前指定的任何任意零值常量表达式。

以下措辞处理表达式的值int()

8.5 初始化器 [dcl.init]

对 T 类型的对象或引用进行零初始化意味着:

[省略不适用的条款]

如果 T 是标量类型(3.9),则将对象设置为值 0(零),作为整数常量表达式,转换为 T

[...]

对 T 类型的对象进行值初始化意味着:

— 如果 T 是具有用户提供的构造函数(12.1)的(可能是 cv 限定的)类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数,则初始化是非良构的);

[省略不适用的条款]

否则,对象被零初始化。

初始值设定项为空括号集的对象,即 (),应进行值初始化。

对于 的值int{}

8.5.4 列表初始化[dcl.init.list]

类型 T 的对象或引用的列表初始化定义如下:

— 如果初始值设定项列表没有元素并且 T 是具有默认构造函数的类类型,则对象是值初始化的。

[省略不适用的条款]

否则,如果初始化列表没有元素,则对象被值初始化。

C++ 工作草案标准 N3337 的所有引用。

于 2013-10-01T18:04:36.223 回答