Warum kann ich eine Referenz in einer Initialisiererliste nicht mit einheitlicher Initialisierung initialisieren?

Lesezeit: 5 Minuten

Warum kann ich eine Referenz in einer Initialisiererliste nicht mit
HighCommander4

Warum bedeutet dies:

struct S {};

struct T
{
    T(S& s) : s{s} {}

    S& s;
};

int main()
{
    S s;
    T t{s};
}

Gib mir einen Compiler-Fehler mit GCC 4.7:

test.cpp: In constructor 'T::T(S&)':
test.cpp:5:18: error: invalid initialization of non-const reference of type 'S&' from an rvalue of type '<brace-enclosed initializer list>'

?

Um den Fehler zu beheben, muss ich die ändern s{s} zu s(s). Bricht das nicht die, ähm, Gleichmäßigkeit der einheitlichen Initialisierung?

BEARBEITEN: Ich habe es mit Clang versucht, und Clang akzeptiert es, also ist es vielleicht ein GCC-Bug?

  • Wenn ich Fragen zu C++ 11 stelle, würde ich für alle Fälle den Compiler und die Version angeben. Nicht alle Compiler unterstützen alle Funktionen, und ich wäre nicht überrascht, Macken zu finden

    – David Rodríguez – dribeas

    9. Mai 12 um 3:57 Uhr

  • @DavidRodríguez-dribeas: guter Punkt, in der Compiler-Version hinzugefügt

    – Oberbefehlshaber4

    9. Mai ’12 um 4:01 Uhr

  • Sie können eine benannte Referenz nicht aus einer Wertreferenz (Initialisierungsliste) initialisieren. Wenn Sie die c ++ – Standereze dazu benötigen, könnte ich Sie auf ein PDF und eine Seitenzahl verweisen. Zu beachten ist auch, dass das refernce , Ihr Referenzobjekt, das eigentlich &S wäre, nur auf der rechten Seite einer Zuweisung steht. Und nein, es bremst nicht die Einheitlichkeit der einheitlichen Initialisierung, Initialisierungslisten sind immer Variablenname (Initlizierer) und durch Kommas getrennt. Zuletzt verifizierbar, kein Komma

    – Johannes

    9. Mai 12 um 4:03 Uhr


  • @johnathon: Ich würde diese Referenz eigentlich wollen, da ich verstehe, dass Sie es tun können. Ich habe eine Antwort mit den meiner Meinung nach angemessenen Zitaten hinzugefügt.

    – David Rodríguez – dribeas

    9. Mai 12 um 4:14 Uhr

  • @DavidRodríguez-dribeas Seite 273.. weiterlesen.

    – Johannes

    9. Mai 12 um 4:21 Uhr

Wofur steht iota von stdiota
Jess gut

Ja, es ist ein Insekt. Das ist etwas Neues und wurde im Arbeitspapier vom Februar 2012 (Verknüpfung).

Nicol Bolas weist darauf hin, dass gcc tatsächlich der konforme Compiler gemäß dem von FDIS genehmigten C++11-Standard ist, da die Änderungen am Arbeitspapier danach vorgenommen wurden.

  • Bitte, Sir, sagen Sie mir, wo in diesem Arbeitspapier in dem Abschnitt, der in diesem Link erwähnt wird, steht, dass Sie eine geklammerte Initialisierungsliste an eine Referenz binden können?

    – Johannes

    9. Mai 12 um 4:28 Uhr

  • OR, wo steht, dass geklammerte Initlizer-Listen in Initlizer-Listen der Implementierung eines Konstruktors verwendet werden können

    – Johannes

    9. Mai ’12 um 4:30 Uhr

  • @johnathon: Der Link führt zu DR 1288, in dem die vorgenommenen Änderungen beschrieben werden (wie von David Rodríguez – dribeas zitiert). In Ihrem Kommentar haben Sie auch die Antwort gegeben in a mem-initializer (12.6.2) von der Norm.

    – Jess Gut

    9. Mai 12 um 4:38 Uhr

  • C++11 heißt so, weil es 2011 genehmigt wurde. Änderungen vorgenommen nach gelten dann nicht, auch wenn es sich um Mängel handelt. Wenn es also nicht im eigentlichen C++11-Standard enthalten ist, dann der Compiler sollen Lehne es ab. Es ist kein Fehler, dies zu tun; es ist ein Fehler akzeptieren es.

    – Nicol Bolas

    9. Mai 12 um 4:47 Uhr


  • @NicolBolas: Ich bin mir nicht sicher, ob das, was Sie sagen, den Konsens in der Compiler-Community widerspiegelt. Compiler implementieren routinemäßig Korrekturen an Fehlerberichten und behandeln sie so, als wären sie Teil des Standards. Das meint das Standard Committee schließlich damit, eine Änderung a zu kennzeichnen Mängelbericht – etwas, das im Standard hätte sein sollen.

    – Oberbefehlshaber4

    9. Mai 12 um 5:12 Uhr

Warum kann ich eine Referenz in einer Initialisiererliste nicht mit
David Rodríguez – dribeas

Ich halte das für einen Fehler im Compiler. Die beiden Absätze, die sich mit der Referenzinitialisierung durch befassen Listeninitialisierung sind (in n3337):

§8.5.4/3

Die Listeninitialisierung eines Objekts oder einer Referenz vom Typ T ist wie folgt definiert:

  • Andernfalls, wenn die Initialisiererliste ein einzelnes Element vom Typ E enthält und entweder T kein Referenztyp ist oder der referenzierte Typ referenzbezogen auf E ist, wird das Objekt oder die Referenz von diesem Element initialisiert; Wenn eine einschränkende Konvertierung (siehe unten) erforderlich ist, um das Element in T zu konvertieren, ist das Programm falsch formatiert.

  • Andernfalls, wenn T ein Referenztyp ist, wird ein temporäres prvalue des Typs, auf den T verweist, listeninitialisiert, und die Referenz wird an dieses Temporäre gebunden. [ Note: As usual, the binding will fail and the program is ill-formed if the reference type is an lvalue reference to a non-const type. — end note ]

Der Compiler scheint den letzten Absatz anzuwenden, obwohl er den ersten anwenden sollte, as referenzbezogen ist definiert als

8.5.3/4

Bei den gegebenen Typen „cv1 T1“ und „cv2 T2“ ist „cv1 T1“ referenzbezogen auf „cv2 T2“, wenn T1 derselbe Typ wie T2 ist oder T1 eine Basisklasse von T2 ist.

Im Fall der Frage sind die Typen der Referenz und des Initialisierers innerhalb der Klammer-Initialisierungsliste genau gleich, was bedeutet, dass die Initialisierung gültig sein sollte.


Im FDIS-Entwurf hatten die entsprechenden Absätze die umgekehrte Reihenfolge. Die Implikation ist, dass der FDIS-Entwurf (n3290) dies nicht zuließ Klammerlisten-Initialisierung von *lvalue*s. Andererseits scheint es beim Lesen des Textes offensichtlich, dass es sich um a handelt Insekt im Standard und dass die Absicht die Reihenfolge von n3337 hatte:

  • Andernfalls, wenn T ein Referenztyp ist, wird ein temporäres prvalue des Typs, auf den T verweist, listeninitialisiert, und die Referenz wird an dieses Temporäre gebunden.

  • Andernfalls, wenn die Initialisierungsliste ein einzelnes Element enthält, wird das Objekt or Hinweis wird von diesem Element initialisiert; Wenn eine einschränkende Konvertierung (siehe unten) erforderlich ist, um das Element in T zu konvertieren, ist das Programm falsch formatiert.

Die Reihenfolge in diesem Dokument bedeutet, dass, weil alle Referenztypen von der ersten Klausel behandelt werden, die Erwähnung Hinweis im folgenden Absatz würde keinen Sinn machen.

1642106165 16 Warum kann ich eine Referenz in einer Initialisiererliste nicht mit
MM

(Hinweis: Ich schreibe diese Antwort mit dem Vorteil von 2 Jahren Rückblick seit der ursprünglichen Frage und um einige der Informationen aus Kommentaren in eine tatsächliche Antwort einzufügen, damit sie durchsucht werden kann).


Initialisieren Sie natürlich eine Referenz vom Typ S& mit einer Referenz auch vom Typ S& soll direkt binden.

Das Problem ist ein Defekt im C++11-Standard und wurde angesprochen von DR1288. Der korrigierte Text wird in C++14 angezeigt.

Das Komitee hat klargestellt, dass der korrigierte Text das ist, was für C++11 vorgesehen war, und daher sollte ein „konformer Compiler“ die korrigierte Version implementieren.

g++ 4.8 folgte dem veröffentlichten Text des C++11-Standards; Als dieses Problem jedoch ans Licht kam, implementierte g++ 4.9 die korrigierte Version, sogar mit -std=c++11 schalten.

Beachten Sie, dass das Problem auch nicht auf Konstruktor-Initialisierungslisten beschränkt ist, z. S s; S &t{s}; funktioniert nicht in g ++ 4.8, tut es auch nicht S s; S &t = s; S &u { t };

.

490880cookie-checkWarum kann ich eine Referenz in einer Initialisiererliste nicht mit einheitlicher Initialisierung initialisieren?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy