次のプログラムを検討してください。
#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]
...およびclang 3.1
main.cpp:5:28: warning: suggest braces around initialization of subobject [-Wmissing-braces]
std::array<int, 1> x = { 0 };
標準に関する限り、少なくともこの例では、二重中括弧と単一中括弧の間に違いはないはずです。
警告に対処するには、2つの方法があります。
何を提案しますか?私見、二重巻きの表現はややsomewhatいように見えます。一方、より複雑な例では、警告によって実際の問題が検出される場合があります。警告があなたを助けたであろう例を知っていますか?
-Wmissing-braces
はGCCの-Wall
(C++モードの場合)、4.8の時点で、あなたが説明する正確な理由によります。 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 };
ここで、initializer-listは、型がTに変換可能な最大N個の要素のコンマ区切りリストです。
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を見ると、 'initializer-list'にオプションで 'initializer-clause'を含めることができます。したがって、どちらの方法も正しいはずです。仕様にもとづきますが、個人的には、単一の波括弧はstd :: array initializer-listのコンパイラ警告を出力すべきではなく、二重の波括弧は過剰です。
Clang 6.0は、括弧の欠落に関する警告を抑制します。 svnログは言う:
それ自体が集約である単一のフィールドで構造体を集約初期化するとき、-Wmissing-braces警告を抑制します。 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=%d\n", 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};
^
要約すれば:
-Wno-missing-braces -Wmissing-field-initializers
をお勧めします。他の有用な警告を失うことなく警告を黙らせるstd::array<int, 1> x = { 0 };
の例では文句を言わないので、警告を無効にする必要はありません。ただし、-Wmissing-field-initializers
では有効にならないため、-Wextra
を有効にする(または-Wall
を使用する)ことをお勧めします。