Considérez le programme suivant:
#include <array>
int main()
{
std::array<int, 1> x = { 0 }; // warning!
x = { { 0 } }; // no warning
return 0;
}
La première initialisation entraîne des avertissements sur gcc 4.7.2 ...
main.cpp:5:22: warning: unused variable ‘x’ [-Wunused-variable]
... et le bruit 3.1
main.cpp:5:28: warning: suggest braces around initialization of subobject [-Wmissing-braces]
std::array<int, 1> x = { 0 };
En ce qui concerne la norme, il ne devrait pas y avoir de différence entre les accolades doubles ou simples, au moins dans cet exemple.
Il existe deux façons de gérer l'avertissement:
Que proposez vous? À mon humble avis, la double expression bouclée semble quelque peu moche. D'un autre côté, l'avertissement peut détecter des problèmes réels dans des exemples plus compliqués. Connaissez-vous un exemple où l'avertissement vous aurait aidé?
-Wmissing-braces
ne sera plus activé dans le GCC -Wall
(pour le mode C++), à partir de la version 4.8, précisément pour la raison que vous décrivez. Pour les versions actuelles de GCC, désactivez ou ignorez l'avertissement, le code que vous avez est écrit comme il se doit.
L'avertissement est probablement destiné à couvrir du code tel que
struct A { int a; int b; };
struct B { A a; int b; };
B b = {
1,
2 // initialises b.a.b, not b.b
};
Cependant, à mon humble avis, cela est déjà suffisamment bien géré par -Wmissing-field-initializers
, qui ne vous avertit pas de votre code d'origine.
Je reçois le même avertissement dans Xcode 6.1.1 (la version actuelle en date du 9 mars 2015). Lorsque j'ajoute les accolades supplémentaires autour de chaque sous-objet, j'obtiens une erreur. Lorsque j'ajoute un ensemble supplémentaire d'accolades autour de la liste d'initialisation entière, l'avertissement disparaît. Selon la spécification standard 14882: 2011 23.3.2.1 [array.overview] le paragraphe 2 indique explicitement
array<T, N> a = { initializer-list };
où initializer-list est une liste séparée par des virgules de jusqu'à N éléments dont les types sont convertibles en T
résultat du code dans Xcode 6.1.1 (ci-dessous)
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
Lorsque nous regardons la sous-section 1 de 14882: 2011 8.5 [dcl.init], nous voyons qu'une "liste d'initialisation" peut éventuellement contenir une "clause d'initialisation", qui elle-même peut être une "liste d'initiation contreventée". Donc, dans les deux cas, cela devrait être correct. Bien que basé sur la spécification, je pense personnellement que les accolades simples ne devraient pas produire un avertissement du compilateur pour une liste d'initialisation std :: array, et les accolades doubles sont excessives.
Clang 6.0 supprime l'avertissement concernant les accolades manquantes. Le journal svn indique:
Supprimez l'avertissement -Wmissing-braces lors de l'initialisation d'agrégat d'une structure avec un seul champ qui est lui-même un agrégat. En C++, une telle initialisation des types std :: array est garantie de fonctionner par la norme, est complètement idiomatique, et l'alternative "suggérée" de Clang n'était pas valide techniquement.
Je voudrais donc omettre les accolades et désactiver -Wmissing-braces
pour Clang antérieur à 6.0 s'il doit être pris en charge.
Lorsque vous ignorez l'avertissement Clang avec -Wno-missing-braces
, Je recommanderais d'activer -Wmissing-field-initializers
(Ou utiliser -Wextra
, qui l'inclut également). Sinon, vous manquez un avertissement utile comme dans cet exemple:
#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)
À titre de comparaison, voici ce que fait 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};
^
En résumé:
-Wno-missing-braces -Wmissing-field-initializers
pour désactiver l'avertissement sans perdre d'autres avertissements utilesstd::array<int, 1> x = { 0 };
exemple, il n'est donc pas nécessaire de désactiver les avertissements. Cependant, je recommanderais d'activer -Wmissing-field-initializers
(Ou utiliser -Wextra
), car il n'est pas activé par -Wall
.