C++98花括号const标量初始化

5

我发现了一段我不理解的代码。这是一个简化版本:

template <int> struct A {};

int const i = { 42 };
typedef A<i> Ai;

int const j = 42;
typedef A<j> Aj;

这段代码在C++98模式下可以使用GCC编译,但不能使用Clang。Clang会产生以下错误:

$ clang -Wall -Wextra -std=c++98 -c test.cpp

test.cpp:4:11: error: non-type template argument of type 'int' is not an integral constant expression
typedef A<i> Ai;
          ^
test.cpp:4:11: note: initializer of 'i' is not a constant expression
test.cpp:3:11: note: declared here
int const i = { 42 };
          ^

据我所知,使用大括号和不使用大括号初始化int应该是等价的。Clang正确地将i初始化为42,只是认为它不是编译时常量。这段代码在C++11模式下编译良好。
为什么j被视为编译时常量而i不是?还是这只是Clang中的一个bug?
更新:我在LLVM bug跟踪器中开了一个ticket来处理这个问题。

我会说这是编译器的一个错误。 - Raxvan
3
这是一个非常大胆的陈述……考虑到它在C++11中有效而在C++98中无效,似乎是有意为之的,所以我实际上期望它符合规格(在Clang方面),而gcc通常会更宽容。 - Matthieu M.
@MatthieuM.:我认为这就是他想要说的:这是gcc的一个bug。没有C++98的语法可以解决这个问题,clang正确地拒绝了它。因此,尽管不符合C++98标准,在gcc中接受它是一个bug。 - PlasmaHH
我现在正在查找98标准以获取所有数据。 - Raxvan
3个回答

6
是的,根据C++98标准8.5/13,这两个声明是等效的:
如果T是一个标量类型,则以下形式的声明
```c++ T object = initializer; ```
和以下形式的声明
```c++ T object(initializer); ```
等效。
T x = { a };

is equivalent to

T x = a;

因此,这两个变量都是常量,并且从一个常量表达式初始化,所以(据我所知)两者都可以用作常量表达式。


2
编译器错误指出 "模板类型参数'int'不是一个整型常量表达式",针对 int const i = { 42 }; 根据98标准,模板参数应该属于以下类别之一:

14.3.2 / 1

非类型、非模板模板参数的模板参数必须是以下之一:

  • 整数或枚举类型的整数常量表达式;或者

...

而整数常量表达式的定义 int const i 属于以下类别:

5.19 常量表达式

整数常量表达式只能包含字面值(2.13)、枚举器、常量变量或静态数据成员

对于 i 的初始化(正如 Mike Seymour 所发帖子的内容):
英译中:

8.5 初始化器 /13

如果 T 是标量类型,则形式为

T x = { a };

的声明等同于

T x = a;

现在根据this postconst intint const 的声明应该是相同的(无法在标准中找到具体说明),使得 i 成为一个常量变量。因此,无论使用哪种初始化方法,对 i 的任何使用都应该是一个整数常量表达式。看起来 clang 中存在一个 bug。查阅网络时,我没有找到一个 bug 报告,只有两个或多个类似的报告:

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=666539

and

http://lists.cs.uiuc.edu/pipermail/llvmbugs/2011-March/017353.html


1
我认为Clang是正确的。初始化列表不是一个表达式。聚合对象和基本对象的初始化是有区别的。当POD对象被初始化时,每个初始化器可以被视为常数表达式。但是,当你处理基本类型时,初始化列表不是一个表达式,也不是常数表达式。
在标准的第14段中写道:
“当初始化器是用大括号括起来的或者是由表达式括号括起来的列表时,源类型未定义。”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接