C++ 0,int()和int{}之间有什么区别?

C++ 0,int()和int{}之间有什么区别?,c++,gcc,clang,zero,compile-time-constant,C++,Gcc,Clang,Zero,Compile Time Constant,由于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()
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
    
    请参阅和消息。我怀疑这是两个编译器中的一个错误,因为我希望它们在这种情况下可以互换,但我很高兴被证明是错误的。:-)

  • 传递到类模板时:

    template<int N> struct X{};
    
    X<0>      x1; //ok
    X<int{}>  x2; //ok (same as X<0>)
    X<int()>  x3; //error  
    
    模板结构X{};
    x1//好啊
    x2//ok(与X相同)
    xx3//错误
    
    请参阅和消息

    我发现语法
    X
    非常熟悉,因为我以前见过(可能使用过)类似的语法,比如在
    std::function
    中,模板参数
    int()
    应该是函数类型(而不是
    0
    ),不带参数,返回
    int
    。但是我想知道规范中的哪一部分,在这个上下文中说,
    int()
    将被视为函数类型,而不是等同于
    int{}
    ,后者总是
    0

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

两个表达式均满足5.19常数表达式[expr.const]中规定的常数表达式要求

关于
X
,本标准规定
int()
在此上下文中不解释为表达式:

14.3模板参数[临时参数] 在模板参数中,类型id和表达式之间的歧义被解析为类型id,而与相应模板参数的形式无关

关于指针转换:

4.10指针转换[conv.ptr] 空指针常量是一个整数类型的整数常量表达式(5.19),其计算结果为零 或类型为
std::nullptr\u t
的PR值

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

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++工作草案标准N33 37。

这基本上是一个“GRIP标准”,对吧?我也喜欢。这是一个非常好的问题——我的印象是,标准并不明确(但我仍在研究它)。@SteveJessop你认为最令人烦恼的解析适用于这里的任何案例吗?我看不到它,除了
X
。即使如此,我认为编译器首先会找到
X
,因此知道它不是在寻找类型。关于
X
:14.3[temp.arg]“在模板参数中,类型id和表达式之间的歧义会被解析为类型id,而不管相应模板参数的形式如何。”@SteveJessop Yes。这一点在我看来也有问题。C++通常试图避免语义信息来驱动解析。在
X
的情况下,语法上下文允许类型声明,因此除非标准要求编译器考虑语义信息(模板参数不是类型参数),否则它是类型声明(和另一个最麻烦的解析实例。有关prvalue的定义,请参见3.10[basic.lval]这个定义包括literal
0
。然后CWG的观点发生了变化,因为之前已经提出了哪些整数表达式是有效的空指针常量的问题。当时我们明确允许NPC使用
false
。但不是
1-1
,因为这早于
constepr
,因此我们没有办法ress什么是“const够了”。@MSalters博士903中还有一个补充说明:在波特兰(2012年10月)会议上,有人提出了担忧