Erwägen:
struct Person
{
int height;
int weight;
int age;
};
int main()
{
Person p { .age = 18 };
}
Der obige Code ist in C99 legal, in C ++ 11 jedoch nicht.
Was war der c ++ 11 Begründung des Standardausschusses, die Unterstützung für eine solche praktische Funktion auszuschließen?
OVERLAPPED
ist ein solches Beispiel. In der Lage zu sein, zu schreiben,={.Offset=12345};
würde den Code viel klarer (und wahrscheinlich weniger fehleranfällig) machen. BSD-Sockel sind ein ähnliches Beispiel.main
ist nicht legal C99. Es sollte lesenstruct Person p = { .age = 18 };
Antworten:
C ++ hat Konstruktoren. Wenn es sinnvoll ist, nur ein Mitglied zu initialisieren, kann dies im Programm durch Implementierung eines geeigneten Konstruktors ausgedrückt werden. Dies ist die Art von Abstraktion, die C ++ fördert.
Auf der anderen Seite geht es bei der Funktion für bestimmte Initialisierer eher darum, Mitglieder direkt im Client-Code verfügbar zu machen und ihnen den Zugriff zu erleichtern. Dies führt zu Dingen wie einer Person im Alter von 18 (Jahren?), Aber mit einer Größe und einem Gewicht von Null.
Mit anderen Worten, bestimmte Initialisierer unterstützen einen Programmierstil, bei dem Interna verfügbar gemacht werden, und der Client erhält die Flexibilität, zu entscheiden, wie er den Typ verwenden möchte.
C ++ ist mehr daran interessiert, die Flexibilität auf die Seite des Designers eines Typs zu legen, damit Designer es einfach machen können, einen Typ richtig und falsch zu verwenden. Dazu gehört, dass der Designer die Kontrolle darüber hat, wie ein Typ initialisiert werden kann: Der Designer bestimmt Konstruktoren, Initialisierer in der Klasse usw.
quelle
Person
bereitzustellen, dass der Autor den Benutzern die größtmögliche Flexibilität beim Festlegen und Initialisieren der Mitglieder bieten wollte? Der Benutzer kann auch schon schreibenPerson p = { 0, 0, 18 };
(und das aus guten Gründen).Person
hat ein sehr C-Design, daher können C-Funktionen sinnvoll sein. C ++ ermöglicht jedoch wahrscheinlich ein besseres Design, wodurch auch die Notwendigkeit ausgewiesener Initialisierer entfällt. - Meiner Ansicht nach entspricht die Aufhebung der Beschränkung für Klasseninitialisierer für Aggregate viel mehr dem Ethos von C ++ als den festgelegten Initialisierern.Am 15. Juli 17 wurde P0329R4 in die aufgenommenc ++ 20Standard: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0329r4.pdf
Dies bringt begrenzte Unterstützung fürc99Designated Initializers. Diese Einschränkung wird in C.1.7 [diff.decl] .4 wie folgt beschrieben:
Die folgenden designierten Initialisierungen, die in C gültig sind, sind in C ++ eingeschränkt:
struct A a = { .y = 1, .x = 2 }
ist in C ++ ungültig, da Bezeichner in der Deklarationsreihenfolge der Datenelemente erscheinen müssenint arr[3] = { [1] = 5 }
ist in C ++ ungültig, da die vom Array festgelegte Initialisierung nicht unterstützt wirdstruct B b = {.a.x = 0}
ist in C ++ ungültig, da Bezeichner nicht verschachtelt werden könnenstruct A c = {.x = 1, 2}
ist in C ++ ungültig, da entweder alle oder keine der Datenelemente von Bezeichnern initialisiert werden müssenZum c ++ 17und früher hat Boost tatsächlich Unterstützung für Designated Intializers und es gab zahlreiche Vorschläge, um die Unterstützung für die hinzuzufügenc ++Standard, zum Beispiel: n4172 und Daryle Walkers Vorschlag, Initialisierern eine Bezeichnung hinzuzufügen . Die Vorschläge zitieren die Umsetzung vonc99Designated Initializers in Visual C ++, gcc und Clang behaupten:
Das Standardkomitee lehnt solche Vorschläge jedoch wiederholt ab und erklärt:
Die Kommentare von Ben Voigt haben mir geholfen, die unüberwindlichen Probleme mit diesem Ansatz zu erkennen. gegeben:
In welcher Reihenfolge würden diese Funktionen aufgerufen? c99:
struct X foo = {.a = (char)f(), .b = g(), .c = h()}
? Überraschenderweise inc99::(Visual C ++, gcc und Clang scheinen ein vereinbartes Verhalten zu haben, da sie alle die Anrufe in dieser Reihenfolge tätigen werden :)
h()
f()
g()
Die Unbestimmtheit des Standards bedeutet jedoch, dass bei einer Interaktion dieser Funktionen auch der resultierende Programmstatus unbestimmt wäre und der Compiler Sie nicht warnen würde : Gibt es eine Möglichkeit, sich vor schlecht benommenen designierten Initialisierern zu warnen ?c ++ hat strenge Anforderungen an die Initialisierungsliste 11.6.4 [dcl.init.list] 4:
So c ++ Für den Support wäre dies in der folgenden Reihenfolge erforderlich gewesen:
f()
g()
h()
Kompatibilität mit früheren brechen c99Implementierungen.
Wie oben erläutert, wurde dieses Problem durch die Einschränkungen für Designated Initializers umgangen, die in akzeptiert wurdenc ++ 20. Sie bieten ein standardisiertes Verhalten und garantieren die Ausführungsreihenfolge der Designated Initializers.
quelle
struct X { int c; char a; float b; }; X x = { .a = f(), .b = g(), .c = h() };
Der Aufruf vonh()
wird vor entwederf()
oder ausgeführtg()
. Wenn die Definition vonstruct X
nicht in der Nähe ist, wird dies sehr überraschend sein. Denken Sie daran, dass Initialisiererausdrücke nicht nebenwirkungsfrei sein müssen.Ein bisschen Hackery, also nur zum Spaß teilen.
Und benutze es wie:
was erweitert zu:
quelle
$
vom Typ TypT
, und Sie weisen seine Mitglieder direkt zu, bevor Sie es zurückgeben. Raffiniert. Ich frage mich, ob es irgendwelche Leistungsprobleme gibt.Bestimmte Initialisierer sind derzeit in C ++ 20 enthalten: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0329r4.pdf, damit wir sie endlich sehen können!
quelle
&
Bediener die Adresse zurückkommen würde , dass das Objekt wird während seiner gesamten Lebensdauer hat).Zwei Kernfunktionen von C99 , die in C ++ 11 fehlen, erwähnen „Designated Initializers and C ++“.
Ich denke, der "designierte Initialisierer" bezog sich auf eine mögliche Optimierung. Hier verwende ich als Beispiel "gcc / g ++" 5.1.
Wir wussten zur Kompilierungszeit, dass
a_point.x
Null ist, also konnten wir erwarten, dass diesfoo
zu einer einzigen optimiert wirdprintf
.foo
istx == 0
nur für den Druck optimiert .Für die C ++ - Version
Und dies wird vom optimierten Assemble-Code ausgegeben.
Wir können sehen, dass dies
a_point
nicht wirklich ein Wert für die Kompilierungszeitkonstante ist.quelle
constexpr point(int _x,int _y):x(_x),y(_y){}
. Der Optimierer von clang ++ scheint den Vergleich auch in Ihrem Code zu eliminieren. Dies ist also nur ein QoI-Problem.struct addrinfo
oder tunstruct sockaddr_in
, sodass Sie Aufgaben haben, die von Deklarationen getrennt sind.