请考虑以下程序:
#include <array>
int main()
{
std::array<int, 1> x = { 0 }; // warning!
x = { { 0 } }; // no warning
return 0;
}
第一次初始化会导致 gcc 4.7.2 上的警告...
main.cpp:5:22: warning: unused variable ‘x’ [-Wunused-variable]
。和叮当 3.1
main.cpp:5:28: warning: suggest braces around initialization of subobject [-Wmissing-braces]
std::array<int, 1> x = { 0 };
就标准而言,至少在本例中,双花括号或单花括号之间应该没有区别。
有两种方法可以处理警告:
- 只需将其关闭即可
- 修复代码,让编译器满意
你有什么建议?恕我直言,双卷曲的表情看起来有些丑陋。另一方面,警告可能会在更复杂的示例中检测到实际问题。您知道警告对您有帮助的示例吗?
4.8 开始,-Wmissing-braces
将不再在 GCC 的-Wall
(对于C++模式)中启用,原因正是您描述的原因。对于当前版本的 GCC,禁用或忽略警告,您拥有的代码将按应有的方式编写。
该警告可能旨在涵盖诸如
struct A { int a; int b; };
struct B { A a; int b; };
B b = {
1,
2 // initialises b.a.b, not b.b
};
但是,恕我直言,这已经被 -Wmissing-field-initializers
处理得足够好了,它不会警告您的原始代码。
我在 Xcode 6.1.1(截至 2015 年 3 月 9 日的当前版本)中收到相同的警告。 当我在每个子对象周围添加额外的大括号时,我得到一个错误。 当我在整个初始化列表周围添加一组额外的大括号时,警告就会消失。 根据标准规范 14882:2011 23.3.2.1 [array.overview] 小节 2 明确指出
array<T, N> a = { initializer-list };
其中初始值设定项列表是最多 N 个元素的逗号分隔列表 其类型可转换为 T
Xcode 6.1.1 中的代码结果(如下)
array<int, 2> key1 = {1, 2}; // warning: suggest braces around initialization of subobject
array<int, 2> key2 = { {1}, {2} }; // error: no viable overload =
array<int, 2> key3 = array<int, 2> { {1}, {2} }; // error: excess elements in struct initializer
array<int, 2> key4 = { {1, 2} }; // no warning and no error
当我们查看 14882:2011 8.5 [dcl.init] 小节 1 时,我们看到"初始值设定项列表"可以选择包含"初始值设定项子句",该子句本身可以是"大括号初始化列表"。 所以无论哪种方式都应该是正确的。 虽然基于规范,我个人认为单大括号不应该为 std::array 初始值设定项列表输出编译器警告,而双大括号是矫枉过正的。
Clang 6.0 禁止显示有关缺少大括号的警告。svn 日志说:
因此,如果需要当聚合初始化具有单个字段(本身就是聚合)的结构时,禁止显示 -Wmissing 大括号警告。在C++中,std::array 类型的这种初始化保证按照标准工作,完全是惯用的,并且"建议"的替代方案来自 Clang在技术上是无效的。
支持,我会省略大括号并禁用 6.0 之前的 Clang -Wmissing-braces
。
当忽略带有 -Wno-missing-braces
的 Clang 警告时,我建议启用 -Wmissing-field-initializers
(或使用 -Wextra
,它也包括它)。否则,您将错过有用的警告,如以下示例所示:
#include <cstdio>
struct A
{
int i;
int arr[2];
int j;
};
void print(const A& a)
{
printf("i=%d, arr={%d,%d}, j=%dn", a.i, a.arr[0], a.arr[1], a.j);
}
int main() {
A a = {1, 2, 3}; // this is the critical line
print(a); // output: i=1, arr={2,3}, j=0
A b = {1, {2}, 3};
print(b); // output: i=1, arr={2,0}, j=3
A c = {1, {2,0}, 3};
print(c); // output: i=1, arr={2,0}, j=3
return 0;
}
$ clang++ -Wall example.cpp
example.cpp:16:13: warning: suggest braces around initialization of
subobject [-Wmissing-braces]
A a = {1, 2, 3};
^~~~
{ }
1 warning generated.
$ clang++ -Wall -Wno-missing-braces example.cpp
(no warnings)
$ clang++ -Wall -Wno-missing-braces -Wmissing-field-initializers example.cpp
example.cpp:16:17: warning: missing field 'j' initializer
[-Wmissing-field-initializers]
A a = {1, 2, 3};
^
1 warning generated.
$ clang++ --version
clang version 3.8.1 (tags/RELEASE_381/final)
为了进行比较,这是GCC所做的:
$ g++ -Wall -Wextra example.cpp
(no warning)
$ g++ -Wall -Wmissing-field-initializers example.cpp
example.cpp: In function ‘int main()’
example.cpp:16:17: warning: missing initializer for member ‘A::j’ [-Wmissing-field-initializers]
A a = {1, 2, 3};
^
总结:
- 对于 Clang,我建议
-Wno-missing-braces -Wmissing-field-initializers
在不丢失其他有用警告的情况下静音警告 - GCC 在原始
std::array<int, 1> x = { 0 };
示例中不会抱怨,因此无需禁用任何警告。但是,我建议启用-Wmissing-field-initializers
(或使用-Wextra
),因为它不是由-Wall
启用的。