C ++ 11: Std :: Array-Initialisierung korrigieren?

69

Wenn ich ein std :: -Array wie folgt initialisiere, warnt mich der Compiler vor fehlenden geschweiften Klammern

std::array<int, 4> a = {1, 2, 3, 4};

Dies behebt das Problem:

std::array<int, 4> a = {{1, 2, 3, 4}};

Dies ist die Warnmeldung:

missing braces around initializer for 'std::array<int, 4u>::value_type [4] {aka int [4]}' [-Wmissing-braces]

Ist dies nur ein Fehler in meiner Version von gcc oder wird es absichtlich gemacht? Wenn ja warum?

Byzanz
quelle
3
std::arrayist ein Aggregat. Ich denke jedoch, dass sie es in Zukunft mit einem Set zum Laufen bringen könnten.
Chris
@chris Was genau meinst du damit?
Byzanz
4
Nun, wissen Sie, wie Sie es mit haben struct S {int i; int j;};und initialisieren können S s = {5, 6};? Das ist eine aggregierte Initialisierung. std::arrayenthält ein eingebautes Array, das über eine Initialisierungsliste initialisiert werden kann. Dies ist die innere Menge. Der äußere Satz dient zur aggregierten Initialisierung.
Chris
@chris Also ist in meinem Fall "{1, 2, 3, 4}" nur ein std :: initializer_list-Objekt, das selbst in die eigentlichen Initialisierungsklammern gesetzt werden muss?
Byzanz
Nun, ich bin mir nicht ganz sicher, wie integrierte Array-Initialisierungslisten nach der Einführung dieses Typs behandelt werden, aber das ist der Kern davon, ja. Einer ist für die Klasse und der andere für das Array innerhalb der Klasse.
Chris

Antworten:

49

Dies ist die bloße Implementierung von std::array:

template<typename T, std::size_t N>
struct array {
    T __array_impl[N];
};

Es ist eine aggregierte Struktur, deren einziges Datenelement ein traditionelles Array ist, sodass das innere {}zum Initialisieren des inneren Arrays verwendet wird.

Die Klammerelision ist in bestimmten Fällen mit aggregierter Initialisierung zulässig (wird jedoch normalerweise nicht empfohlen). Daher kann in diesem Fall nur eine Klammer verwendet werden. Siehe hier: C ++ - Vektor von Arrays

Pubby
quelle
Alle Versionen des Standards ermöglichen die Klammerentfernung.
Cubbi
Huh, dumme GCC-Warnungen>.> Mir war nicht bewusst, dass dies bereits der Fall war.
Chris
Ich hatte das gleiche Problem (bis jetzt 2016), aber ich habe es mit der folgenden Syntax behoben: 'std :: array <int, 4> a [] = {1,2,3,4};' Also habe ich eckige Klammern anstelle von verschachtelten geschweiften Klammern hinzugefügt. Vielleicht weiß jemand, warum diese Variante bei mir funktioniert hat?
Sam
5
@ Sam Das hat eine andere Bedeutung. Die von Ihnen veröffentlichte Syntax erstellt ein Array von std :: arrays (ein zweidimensionales Array) anstelle eines einzelnen Arrays (eindimensional).
Pubby
36

Nach cppreference . Doppelklammern sind nur erforderlich, wenn sie =weggelassen werden.

// construction uses aggregate initialization
std::array<int, 3> a1{ {1,2,3} };    // double-braces required
std::array<int, 3> a2 = {1, 2, 3}; // except after =
std::array<std::string, 2> a3 = { {std::string("a"), "b"} };
Draco Ater
quelle
4
@cyberpunk_ nur, wenn Ihr Compiler DR # 1270 implementiert hat, wodurch diese Einschränkung aufgehoben wird .
Cubbi
@Chubbi Aber warum gibt es mir dann eine Warnung für "std :: array <int, 4> a = {1, 2, 3, 4}"?
Byzanz
@cyberpunk_ Es ist nur eine falsche Warnung.
Cubbi
4
@cyberpunk_ Sie können es trivial mit den zusätzlichen Klammern befriedigen. Es ist nicht die einzige nervige Warnung, die GCC (jemals gesehen suggest parentheses around ‘&&’ within ‘||’?)
Hat
2
Die Warnung bedeutet, dass der Compiler-Writer der Meinung ist, dass Sie möglicherweise nicht klug genug sind, um diese Sprachfunktion korrekt zu verwenden.
Pete Becker
6

In C ++ 11 vor dem CWG 1270 sind doppelte Klammern erforderlich (in C ++ 11 nach der Überarbeitung und in C ++ 14 und darüber hinaus nicht erforderlich):

// construction uses aggregate initialization
std::array<int, 3> a1{ {1, 2, 3} }; // double-braces required in C++11 prior to the CWG 1270 revision
                                    // (not needed in C++11 after the revision and in C++14 and beyond)
std::array<int, 3> a2 = {1, 2, 3};  // never required after =

std :: array referenz

Amit G.
quelle
2

C ++ 17 std::array Klassenvorlagenargumentabzug (CTAD)

Diese neue C ++ 17-Funktion wird von der Standardbibliothek verwendet und ermöglicht es uns nun, auch die Vorlagentypen wegzulassen, damit Folgendes funktioniert:

main.cpp

#include <array>

int main() {
    std::array a{1, 2, 3};
}

Anstatt von std::array<int, 3> a{1, 2, 3};

Getestet mit:

g++ -ggdb3 -O0 -std=c++17 -Wall -Wextra -pedantic -o main.out main.cpp

Wenn wir -std=c++14stattdessen zum Beispiel setzen, kann es nicht kompiliert werden mit:

error: missing template arguments before ‘a’

Siehe auch: Größe von std :: array ableiten?

Getestet unter Ubuntu 18.04, GCC 7.5.0.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle