[C++] initializer_list innerhalb einer Zeile benutzen

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
Schrompf
Moderator
Beiträge: 4884
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

[C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von Schrompf »

Moin mal wieder,

ich arbeite oft mit kleinen Helferstrukturen wie z.B.

Code: Alles auswählen

struct Dings { Objekt* obj; float wert; size_t zahl; }
Wenn ich nun Instanzen dieser Helferstruktur anlegen will, muss ich entweder von Hand einen Konstruktor schreiben, der jedes einzelne Element als Parameter nimmt und durchreicht, oder ich benutze die von C bekannte Init-Liste:

Code: Alles auswählen

 Dings d = { obj, wert, zahl };
Nur leider kann ich diese Konstruktion nun nicht innerhalb einer Zeile anwenden. All das folgende geht nicht:

Code: Alles auswählen

vector.push_back( Dings( obj, wert, zahl));
vector.push_back( Dings{ obj, wert, zahl });
vector.push_back( Dings d = { obj, wert, zahl } );
Gibt es einen schicken C++11-Syntax, wie ich in einer Zeile eine Instanz einer Struktur anlegen und elementweise initialisieren kann?

[Edit]Zur Sicherheit: der Compiler ist VS2012 SP1 CTP Nov12, der müsste Initializer Lists können. Behauptet zumindest Microsoft
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von CodingCat »

Folgende Varianten sind gültig:

Code: Alles auswählen

#include <vector>
#include <cstddef>
 
class Objekt;
struct Dings { Objekt* obj; float wert; size_t zahl; };
 
int main()
{
    std::vector<Dings> dings;
    dings.push_back( Dings{ nullptr, 7.0f, 4 } );
    dings.push_back( { nullptr, 7.0f, 4} );
    return 0;
}
Würde mich nicht wundern, wenn die hirnlosen Idioten bei MS das Wichtigste mal wieder vergessen hätten.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
Schrompf
Moderator
Beiträge: 4884
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von Schrompf »

So scheint es, ja. Erstere Version ergibt:

Code: Alles auswählen

error C2275: 'Dings' : illegal use of this type as an expression
error C2143: syntax error : missing ')' before '{'
error C2143: syntax error : missing ';' before '{'
error C2143: syntax error : missing ';' before '}'
error C2059: syntax error : ')'
Zweiteres ohne explizite Angabe des Typs ergibt:

Code: Alles auswählen

error C2664: 'void std::vector<Dings,std::allocator<_Ty>>::push_back(const Dings &)' : cannot convert parameter 2 from 'initializer-list' to 'Dings &&'
with
[
   _Ty=Dings
]
Reason: cannot convert from 'initializer-list' to 'Dings'
Only an initializer-list with zero or one elements can be converted to this type
Letzteres ist evtl. auch nur der Tatsache geschuldet, dass wie von MS berichtet die Standard-Lib noch nicht auf dem aktuellen Stand ist. Ersteres sollte aber einen Konstruktor-Aufruf auslösen, müsste also ein Sprach-Feature und kein Feature der Standardlib sein. Und demzufolge nach meinem Verständnis funktionieren. Schade.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von CodingCat »

Beide sollten zu einem Konstruktoraufruf aufgelöst werden, unabhängig von der STL. :-/
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von dot »

Ich denk in dem Zusammenhang sollte man auch std::vector::emplace_back erwähnen... ;)
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von CodingCat »

dot hat geschrieben:Ich denk in dem Zusammenhang sollte man auch std::vector::emplace_back erwähnen... ;)
Könnte man, allerdings müsste man für emplace_back() wieder mindestens einen Konstruktor schreiben. Dabei ist es SO Zeit, dass diese ewige nutzlose Konstruktorschreiberei endlich aufhört.

Nebenbei kann ich mit emplace_back() noch immer nix anfangen, weil ich überhaupt nicht sehe, welche Parameter erwartet werden. Ich habe das ungute Gefühl, dass in C++11 mit Variadic Templates schon wieder zu minimalistisch und allgemein gegriffen hat. Aber möglicherweise schaffen IDEs in 5-10 Jahren ja sogar eine Propagierung der Parameternamen und -typen. Einfacher wird es jedenfalls nicht.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von dot »

CodingCat hat geschrieben:Könnte man, allerdings müsste man für emplace_back() wieder mindestens einen Konstruktor schreiben. Dabei ist es SO Zeit, dass diese ewige nutzlose Konstruktorschreiberei endlich aufhört.
Das ist richtig, aber ein fehlender Konstruktor ist ja wohl auch das Problem bei den Varianten mit der Initializer List. Dort wird eben überall ein Temporary erzeugt und der Compiler wählt richtig die Variante von push_back aus, die eine rvalue Reference als Parameter nimmt. Am Ende scheitert es wieder mal daran, dass MSVC noch keine impliziten Move Konstruktoren hat...
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von CodingCat »

dot hat geschrieben:Das ist richtig, aber um ein fehlender Konstruktor ist ja wohl auch das Problem bei den Varianten mit der Initializer List. Dort wird eben überall ein Temporary erzeugt und der Compiler wählt richtig die Variante von push_back aus, die eine rvalue Reference als Parameter nimmt. Am Ende scheitert es wieder mal daran, dass MSVC noch keine impliziten Move Konstruktoren hat...
Nein, es scheitert daran, dass MSVC offenbar noch immer keine Initializer-List-Konstruktion kann, sofern kein explizit definierter Initializer-List-Konstruktor vorhanden ist. Dass in diesem Fall mangels impliziter Move-Konstruktoren obendrein nicht verschoben würde, ist richtig, würde jedoch einfach in einer Kopie resultieren, nicht in einem Fehler.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von dot »

Stimmt, die Fehlermeldung sagt eigentlich auch genau das...
Benutzeravatar
Schrompf
Moderator
Beiträge: 4884
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von Schrompf »

Ich hänge übrigens jetzt, anderthalb Jahre später, mit VSVC2013 wieder an dem selben Ärgernis. Anscheinend kann VisualStudio immernoch keine anonymen Instanzen per Uniform Initialization anlegen.

Ich so:

Code: Alles auswählen

sammlung.push_back( MeineStruktur{ a, b, c });
Und darauf er so:
EffingCompiler hat geschrieben:1>c:\projekte\knuiff.cpp(55): error C2143: Syntaxfehler: Es fehlt ')' vor '{'
1>c:\projekte\knuiff.cpp(55): error C2059: Syntaxfehler: ')'
1>c:\projekte\knuiff.cpp(55): error C2143: Syntaxfehler: Es fehlt ';' vor '{'
1>c:\projekte\knuiff.cpp(55): error C2143: Syntaxfehler: Es fehlt ';' vor '}'
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4884
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von Schrompf »

Ok, das war evtl. wieder ein Eigentor. Ich kompiliere ja für verdammte XP-Kompatibilität immernoch mit VC2012-XP-Compiler. Evtl. kann das VC2013 doch schon, ich merk's nur nicht.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von dot »

Schrompf hat geschrieben:Evtl. kann das VC2013 doch schon, ich merk's nur nicht.
Jop, in VS 2013 geht's :)
Spiele Programmierer
Establishment
Beiträge: 426
Registriert: 23.01.2013, 15:55

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von Spiele Programmierer »

Ich benutze ja zur Zeit tatsächlich hauptsächlich eine 2013er CTP Version.
Bei mir steht aber auch "Visual Studio 2013 - Windows XP(v120_xp)" zur Auswahl.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4884
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von Schrompf »

Auch grade festgestellt. Und wenn ich wirklich mächtig Glück habe, reicht es für XP-startfähige Exen aus, das exe-erzeugende Projekt mit dem XP-Compiler zu bauen und die umfangreiche Kette an Libs vorneweg kann alles an C++11-Support nutzen, was Microsoft mir hingeworfen hat.

@v120_xp: jupp, das wär auch ne Variante. Ich habe allerdings meinen Nachmittag mit dem Versuch verschwendet, Boost mit diesem Compiler neuzubauen. Und das ist notwendig, sonst beschwert sich der Linker nachher, dass er v110_xp-gebaute Libs nicht linken kann. Keine Ahnung, wie ich Boost damals für v110_xp gebaut bekommen habe...
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von Krishty »

Leicht off-topic: Wie sind denn deine Erfahrungen mit der 2012er CRT? Ist die breit verfügbar?

Ich benutze noch 100_xp weil ich vor allem nicht möchte, dass die Anwender die Laufzeitbibliothek installieren müssen. Fast jeder XP-Nutzer da draußen hat die Visual C++-2010-CRT installiert, weil sie halt seit fünf Jahren von allen möglichen Tools und Treibern vorausgesetzt wird. Die 2012er/13er CRT bedeutet einen zusätzlichen Download; eine zusätzliche Installation; dabei dann Probleme weil 10 Jahre alte XP-Installationen ihren Windows Installer-Dienst zerschossen haben und Opa seinen Enkel nicht erreichen kann, und der dann sowieso erstmal Vista Windows 7 Windows 8 Windows 8.1 Windows 9 installieren würde.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 4884
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von Schrompf »

Da habe ich keine sinnvollen Statistiken für Dich, nur gefühltes Wissen. Und das lautet: bei Desura hat man erst auf mein Bestreben überhaupt die VS2013-Runtime in die Dependencies aufgenommen. Bei Steam (ein Jahr später) war sie aber ab Start verfügbar. Und da heutzutage praktisch niemand mehr noch Installer runterlädt, ist für mich das Thema damit eigentlich gegessen.

Kannst Du nicht die Runtime statisch linken? Das würde ich ja tun, weil mir Exe-Größen egal sind. Leider müssen dann alle Libs, die man so ansaugt, auch statisch gegen die Runtime linken. Und bei QT ist das quasi unmöglich, als ich es das letzte Mal probiert habe, weswegen ich irgendwann zähneknirschend hingenommen habe, dynamisch zu linken.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8268
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von Krishty »

Statisches Einbinden macht bei mir die Ausnahmebehandlung kaputt, weil ich die erst zur Hälfte selber implementiert habe :( Wenn ich so weit bin, dass statisches Linken klappt, brauche ich die CRT sowieso nicht mehr. Ist nur leider großer Brainfuck, da hinzukommen.

Aber jetzt wo du mich drauf gebracht hast, sollte ich wieder damit anfangen. Letzten Endes würden wohl alle meine Projekte profitieren. Andererseits könnte ich auch einfach auf Ausnahmen verzichten; das würde die Sache noch einfacher machen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
snoob741
Beiträge: 76
Registriert: 03.04.2012, 22:36

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von snoob741 »

Hast Du mal geprüft ob der VC mit Lambda expressions klar kommt? Dann könntest Du auch Einzeiler
in der Form nutzen:

Code: Alles auswählen

	dings.push_back([]()-> Dings { return Dings{nullptr, 7.0f, 4}; }());
Bzw. wenn Du deinem Stuct noch einen Konstruktor verpasst, könntest Du den Lambda expression
auch als delegate factory nutzen:

Code: Alles auswählen

        class Objekt;
	struct Dings 
	{
		Dings(Objekt* o, float w, size_t z):obj(o),wert(w), zahl(z){}
		Objekt* obj; float wert; size_t zahl; 
	};
	
	auto d = [](Objekt* obj, float wert, size_t zahl)-> Dings { return Dings(obj, wert, zahl);};
	
	std::vector<Dings> dings;	
	dings.push_back(d(nullptr, 7.0f, 4));
        dings.push_back(d(nullptr, 0.25f, 1));
Benutzeravatar
Schrompf
Moderator
Beiträge: 4884
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [C++] initializer_list innerhalb einer Zeile benutzen

Beitrag von Schrompf »

Die Ideen sind interessant - ich bin immmer wieder erstaunt, wieviele Wege es in C++ gibt, das selbe Ziel zu erreichen. Die Ideen sind aber leider unpraktisch - mir geht es ja nur darum, etwas Tipparbeit zu sparen. Und wenn ich der Klasse einen Konstruktor gebe, kann ich den auch gleich direkt benutzen:

Code: Alles auswählen

struct Dings 
{
Dings(Objekt* o, float w, size_t z):obj(o),wert(w), zahl(z){}
Objekt* obj; float wert; size_t zahl; 
};

std::vector<Dings> dings;	
dings.push_back(Dings(nullptr, 7.0f, 4));
Ich hatte es dann mit leisem Grummeln in einer Extrazeile gelöst, was ja ganz klassisches C ist:

Code: Alles auswählen

Dings d = { nullptr, 7.0f, 4 };
container.push_back( d);
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Antworten