Bestimmten Code noch kürzer schreiben
-
das Angesprochene Feature von euch beiden ist viel zu eingeschränkt und sonst nirgends sauber verwendbar das man es deswegen ausgelassen hat
zum copy ctor
genau so wie bei const doppelt implementieren
usw. usw.....
-
*"Es löst ein Problem, aber es löst nicht alle anderen => wir warten lieder auf die perfekte Lösung für alles auf einmal (die es nie geben wird)"
*
Ich fand diese Einstellung/Argumentation schon immer sehr [euphemismus]befremdlich[/euphemismus].
Ist das perfekte Totschlagargument um jeglichen Fortschritt zu verhindern.
-
Eine allgemeine Syntax könnte etwa so aussehen:
struct Rechteck { int a, b; constexpr auto members = std::reflect<Rechteck>::public_members; Rechteck(members::type $<members::name>...) : $<members::name>($<members::name>)... { } };Das sind drei neue Sprach-Features:
- Operator ... zum Expandieren von
constexpr-Ranges (geht heute nur mit variadic templates) - das Expandieren mit ... in eine Initialisierungsliste
constexpr-Zeichenketten als Bezeichner. Da ist mir auf die Schnelle nichts besseres eingefallen als$<>
Ein viertes Feature macht solche Konstruktoren wiederverwendbar:
template < class Class, auto members = std::reflect<Class>::public_members > this construct_members(members::type $<members::name>...) : $<members::name>($<members::name>)... { } struct Rechteck { int a, b; using construct_members<Rechteck>; };
- Operator ... zum Expandieren von
-
das Expandieren mit ... in eine Initialisierungsliste
Inwiefern ist das neu?
-
markus2 schrieb:
Weiss jemand, wie ich die Variablennamen nicht zwei mal zusätzlich schreiben bräuchte?
ja, klar:
typedef unsigned u; typedef u short u_s; inline u combine(u_s ah, u_s al){ return (1 << 8*sizeof(u_s)) * ah + al; } struct Foo { u long a; // <- nur noch eine Foo(u_s ah, u_s al) : a(combine(ah, al)){} }; main() { assert(sizeof(u) == 2 * sizeof(u_s)); Foo f(0x8765, 0x7fff); cout << hex << f.a << endl; }- wer schafft's mit null Variablen?
-
haha
typedef u unsignednice

-
typedef unsigned u; u long a;Das ist Unsinn.
-
großbuchstaben schrieb:
- wer schafft's mit null Variablen?
Ich bin ja immer noch ein Fan von Makros zwecks Metaprogrammierung:
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__,9,8,7,6,5,4,3,2,1) #define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N #define ONE_TO_ONE_1(X1) X1(X1) #define ONE_TO_ONE_2(X1,X2) X1(X1), ONE_TO_ONE_1(X2) #define ONE_TO_ONE_3(X1,X2,X3) X1(X1), ONE_TO_ONE_2(X2,X3) #define ONE_TO_ONE_4(X1,X2,X3,X4) X1(X1), ONE_TO_ONE_3(X2,X3,X4) #define ONE_TO_ONE_5(X1,X2,X3,X4,X5) X1(X1), ONE_TO_ONE_4(X2,X3,X4,X5) #define ONE_TO_ONE_6(X1,X2,X3,X4,X5,X6) X1(X1), ONE_TO_ONE_5(X2,X3,X4,X5,X6) #define ONE_TO_ONE_7(X1,X2,X3,X4,X5,X6,X7) X1(X1), ONE_TO_ONE_6(X2,X3,X4,X5,X6,X7) #define ONE_TO_ONE_8(X1,X2,X3,X4,X5,X6,X7,X8) X1(X1), ONE_TO_ONE_7(X2,X3,X4,X5,X6,X7,X8) #define ONE_TO_ONE_9(X1,X2,X3,X4,X5,X6,X7,X8,X9) X1(X1), ONE_TO_ONE_8(X2,X3,X4,X5,X6,X7,X8,X9) #define ONE_TO_ONE_IMPL_LEVEL2(N,...) ONE_TO_ONE_ ## N(__VA_ARGS__) #define ONE_TO_ONE_IMPL(N,...) ONE_TO_ONE_IMPL_LEVEL2(N,__VA_ARGS__) #define ONE_TO_ONE(...) ONE_TO_ONE_IMPL(VA_NUM_ARGS(__VA_ARGS__),__VA_ARGS__) #define REMOVE_TYPES_2(X1,X2) X2 #define REMOVE_TYPES_4(X1,X2,X3,X4) X2,REMOVE_TYPES_2(X3,X4) #define REMOVE_TYPES_6(X1,X2,X3,X4,X5,X6) X2,REMOVE_TYPES_4(X3,X4,X5,X6) #define REMOVE_TYPES_8(X1,X2,X3,X4,X5,X6,X7,X8) X2,REMOVE_TYPES_6(X3,X4,X5,X6,X7,X8) #define REMOVE_TYPES_IMPL_LEVEL2(N,...) REMOVE_TYPES_ ## N(__VA_ARGS__) #define REMOVE_TYPES_IMPL(N,...) REMOVE_TYPES_IMPL_LEVEL2(N,__VA_ARGS__) #define REMOVE_TYPES(...) REMOVE_TYPES_IMPL(VA_NUM_ARGS(__VA_ARGS__),__VA_ARGS__) #define PARAMETER_LIST_2(X1,X2) X1 X2 #define PARAMETER_LIST_4(X1,X2,X3,X4) X1 X2,PARAMETER_LIST_2(X3,X4) #define PARAMETER_LIST_6(X1,X2,X3,X4,X5,X6) X1 X2,PARAMETER_LIST_4(X3,X4,X5,X6) #define PARAMETER_LIST_8(X1,X2,X3,X4,X5,X6,X7,X8) X1 X2,PARAMETER_LIST_6(X3,X4,X5,X6,X7,X8) #define PARAMETER_LIST_IMPL_LEVEL2(N,...) PARAMETER_LIST_ ## N(__VA_ARGS__) #define PARAMETER_LIST_IMPL(N,...) PARAMETER_LIST_IMPL_LEVEL2(N,__VA_ARGS__) #define PARAMETER_LIST(...) PARAMETER_LIST_IMPL(VA_NUM_ARGS(__VA_ARGS__),__VA_ARGS__) #define REMOVE_COMMAS_ADD_SEMICOLONS_2(X1,X2) X1 X2; #define REMOVE_COMMAS_ADD_SEMICOLONS_4(X1,X2,X3,X4) X1 X2;REMOVE_COMMAS_ADD_SEMICOLONS_2(X3,X4) #define REMOVE_COMMAS_ADD_SEMICOLONS_6(X1,X2,X3,X4,X5,X6) X1 X2;REMOVE_COMMAS_ADD_SEMICOLONS_4(X3,X4,X5,X6) #define REMOVE_COMMAS_ADD_SEMICOLONS_8(X1,X2,X3,X4,X5,X6,X7,X8) X1 X2;REMOVE_COMMAS_ADD_SEMICOLONS_6(X3,X4,X5,X6,X7,X8) #define REMOVE_COMMAS_ADD_SEMICOLONS_IMPL_LEVEL2(N,...) REMOVE_COMMAS_ADD_SEMICOLONS_ ## N(__VA_ARGS__) #define REMOVE_COMMAS_ADD_SEMICOLONS_IMPL(N,...) REMOVE_COMMAS_ADD_SEMICOLONS_IMPL_LEVEL2(N,__VA_ARGS__) #define REMOVE_COMMAS_ADD_SEMICOLONS(...) REMOVE_COMMAS_ADD_SEMICOLONS_IMPL(VA_NUM_ARGS(__VA_ARGS__),__VA_ARGS__) #define GENERIC_CLASS_BEGIN(NAME, ...) class NAME { REMOVE_COMMAS_ADD_SEMICOLONS(__VA_ARGS__) public: NAME(PARAMETER_LIST(__VA_ARGS__)) : ONE_TO_ONE(REMOVE_TYPES(__VA_ARGS__)) {} #define GENERIC_CLASS_END };Damit kann man dann schreiben:
GENERIC_CLASS_BEGIN(Foo, int, i, double, d, long, l) void my_method(); GENERIC_CLASS_ENDDies expandiert (nach etwas Formatierung) zu:
class Foo { int i; double d; long l; public: Foo(int i,double d,long l) : i(i), d(d), l(l) {} void my_method(); };Das offensichtliche Problem ist natürlich, dass die Makros selber nicht mehr DRY sind. Wir haben 3x die gleiche Makrokette mit minimalen Unterschieden und eine weitere Makrokette, die ein ähnlich, aber ein bisschen anders ist als die anderen 3. Leider kann man mit Makros keine anderen Makros metaprogrammieren, wir müssen also zu einem externen Präprozessor greifen. Das kann ein manueller Aufruf des C-Präprozessors sein (Sollte ausreichen) oder aber ein mächtigerer Prozessor, wir M4. Das löst auch das Problem der Beschränkung auf 4 Parameter, das mein Code derzeit hat. Das mache ich jetzt aber nicht mehr vor.
-
großbuchstaben schrieb:
- wer schafft's mit null Variablen?
Argh, Mist!
Ich hatte gedacht dass es nebenstd::getenvauch einstd::setenvgibt. Gibt's aber dummerweise nicht
Aber wenn wir einfach mal so täten als ob...
#include <iostream> #include <sstream> #include <string> #include <cstdlib> #include <stdlib.h> #define MEMNAME(name) static_cast<std::stringstream&>(std::stringstream() << static_cast<void const*>(this) << "-" << #name).str().c_str() #define GETMEM(name) static_cast<decltype(this->name())>(std::atoll(std::getenv(MEMNAME(name)))) #define SETMEM(name, val) ::_putenv_s(MEMNAME(name), std::to_string(static_cast<long long>(val)).c_str()) #define INITMEM(name) SETMEM(name, name) #define CLRMEM(name) ::_putenv_s(MEMNAME(name), "") struct Foo { Foo(int a, int b) { INITMEM(a); INITMEM(b); } ~Foo() { CLRMEM(a); CLRMEM(b); } int a() { return GETMEM(a); } int b() { return GETMEM(b); } }; int main() { Foo f(0x8765, 0x7fff); std::cout << std::hex << f.a() << ", " << f.b() << std::endl; }
-
Meine Vorstellung ging eigentlich in eine sehr simple Richtung.
Wenn die Klasse public: und ohne Konstrukor ist, also praktisch nur eine struct, dann erlaubt mir C++ (GCC mit std=c++11 jedenfalls) diese Verwendung:
struct Foo { int a, b; } int main() { Foo{1,2}; }Und das wäre vielleicht noch schöner, wenn mir C++ einen "Konstruktor" erlauben würde, der mir (das tut die initialization list ja auch?) einen Block erlaubt, der ausgeführt wird, nachdem der brace initializer das Seine getan hat.
Also das hier verbietet GCC mir ja, wenn ich zB. mit Foo{1,2} instanzieren möchte:
struct Foo { int a, b; Foo() { } }Das das nicht erlaubt ist, macht sicherlich Sinn. Aber bei der Menge an möglichen Konstruktoren könnte es ja vielleicht für die Brace-initializer auch einen geben?
struct Foo { int a, b; Foo{} { } // man beachte die geschweiften Klammern }Aber gut, ich habe mit C++ die Möglichkeit, eine struct (und in gewissem Maß "kein OOP") zu verwenden, wo ich möchte. Also sei's drum. Mir sind eben oft Features entgangen, weil ich nicht viel modernen Code lese, und deshalb hatte ich die Frage.
-
happystudent schrieb:
Also ich fände es schon praktisch wenn man einige solche Sachen defaulten könnte... Gerade bei Copy-Construktor oder Asignment Zeug ist es sehr nervig wenn man neue Member zu der Klasse hinzufügen will, weil man dann alle Copy-, Asignment- und Move Dinger auch anpassen muss (und nicht mal nen Fehler bekommt wenn mans vergisst).
Sowas wäre cool:
struct foo { std::atomic<bool> b; int i, j; foo (int i, int j) : i(i), j(j), b(false) {} foo (foo const &f) : b(f.b.load()), default {} // Alle restlichen Member default-kopiert foo &operator=(foo const &f) { if (this != &f) { b = f.b.load(); default; // Syntax ist natürlich Verbesserungsfähig^^ } return *this; } // ... };Denn obwohl mir das schon oft passiert ist vergesse ich es immer noch regelmäßig

Du hast da nicht zu wenig default, sondern zu viel default.
Mach die Defaultkonstruktoren weg.
-
volkard schrieb:
Du hast da nicht zu wenig default, sondern zu viel default.
Mach die Defaultkonstruktoren weg.Hä, was für Defaultkonstruktoren? Da gibts keinen Defaultkonstruktor.
TyRoXx schrieb:
Eine allgemeine Syntax könnte etwa so aussehen:
Oder zB so:
struct foo { int i, j; std::atomic<bool> b; foo(int i, int j) : b(false), i(i), j(j) {} foo(foo const &f) : b(f.b.load()), std::reflect<foo>::members_except(b, std::reflect<foo>::default_init(*this, f) ) {} // ... };