Type aus trait benutzen
-
Servus,
mich plagt gerade folgendes Problem:
Es gibt ID-Objekte von folgendem Typ:
template <typename T> struct Id { typedef T Type; int id_; bool flag_; Id(int id, bool flag):id_(id), flag_(flag) {}; };, die sind in einer .h Datei angelegt:
static const Id<float> SOME_ID(23,true); static const Id<int> SOME_OTHER_ID(42,true);Der Benutzer soll sich nicht drum kümmern müssen, dass SOME_ID für floats ist und SOME_OTHER_ID für ints.
Daher ist der typedef vorgesehen, damit man hinterher rauskriegt, was für ein Typ drinsteckt. Das geht aber nicht:
void foo() { SOME_ID::Type t; t = 17; }Geht nicht, weil
14: error: ‘SOME_ID’ is not a class or namespace 37: error: expected ‘(’ before ‘t’ 37: error: expected ‘;’ before ‘t’Mein Ziel ist es, das
SOME_ID::Type t = 17.23;kompiliert wird, aber
SOME_ID::Type t = "foo";nicht, weil ein String nicht in float konvertiert werden kann.
Wie erreiche ich das?
Gruß,
Philipp
-
Hey,
das Problem ist, das du den Scopeoperator :: hier auf eine Instanz anwendest und nicht auf eine Klasse.
Möglich wäre also nur folgendes:typedef Id<float> SOME_ID; static const SOME_ID SomeId(23,true) ... SOME_ID::type t = 3.14;Also, kurz gesagt, du kannst nicht auf type über eine Instanz der Klasse zugreifen, sondern nur über die Klasse selbst.
Gruß Gate
-
Sowas habe ich befürchtet.
Ich habe jetzt Id-Typen statt Id-Objekte draus gemacht:template <typename T, int id, bool flag> struct Id { typedef T Type; static int Id() {return id;} static bool flag() {return flag;} };Eine ID definiere ich mir dann als
typedef Id<float, 23, true> SOME_ID;und man kann den Typ benutzen:
SOME_ID::Type t = 1.0;Das Problem ist jetzt nur, dass es keine gute Möglichkeit mehr gibt, über alle IDs zu iterieren. Das geht jetzt nur noch Typlisten.
Philipp
-
PhilippM schrieb:
Das Problem ist jetzt nur, dass es keine gute Möglichkeit mehr gibt, über alle IDs zu iterieren. Das geht jetzt nur noch Typlisten.
Vielleicht kannst du auch Type Erasure benutzen. Allerdings müsstest du die Typen bei der Typdefinition irgendwo registrieren.
Aber wie hättest du denn über die Variablen verschiedenen Typs iteriert? Kannst du das ein wenig ausführen (auch falls es sich nur um Iterationen über gleiche Typen handelt)?
-
Nexus schrieb:
Vielleicht kannst du auch Type Erasure benutzen. Allerdings müsstest du die Typen bei der Typdefinition irgendwo registrieren.
Das klingt interessant. Wie geht das?
Aber wie hättest du denn über die Variablen verschiedenen Typs iteriert? Kannst du das ein wenig ausführen (auch falls es sich nur um Iterationen über gleiche Typen handelt)?
Völlig korrekt. Die Idee war noch nicht wirklich zuende gedacht. Da muss noch ein bißchen Rotwein drüber getrunken werden

Worum es geht:
Bisher gibts ein pdf wo drin steht, wenn du den Datensatz FOO vom Interface haben willst, dann musst du die request-Funktion mit der numerischen ID 4711 und der Flag false aufrufen, und dann bekommst du irgendwann einen float geschickt.Das ist natürlich völlig Banane, denn Dokumentation wird eh nie gelesen und außerdem sollte ein falscher Aufruf schon so früh wie möglich krachen.
Daher jetzt der Mechanismus: Ich bin an FOO_ID interessiert, dann leg ich mir mal einen FOO::Type an und rufe die request-Funktion mit FOO_ID::id() und FOO_ID::flag() auf. Damit kommt keiner mehr durcheinander und wenn jemand einen inkompatiblen Typ angibt, klopft ihm der Kompiler auf die Finger.
So weit, so gut.Jetzt geistert in meinem Kopf die Idee rum, durch die "Liste" aller verfügbaren IDs (die ja jetzt Typen sind) zu iterieren, um sagen wir mal dynamisch in Qt einen Dialog aufzubauen, der jeden Wert in ein Edit-Feld schreibt oder so.
Ich hoffe, an dem Beispiel wird klar, wo die Reise hingehen soll.
Philipp
-
Du kannst zur Laufzeit nicht über verschiedene Typen iterieren, darum musst du sie vereinheitlichen. Type Erasure nennt man die Technik, von statischen Typinformationen zu abstrahieren, aber Typsicherheit zur Laufzeit zu erhalten.
Dabei geht es darum, ein gemeinsames Interface für die Typen zu erstellen. Du musst dir einen Weg überlegen, wie du Typen überhaupt ansprechen willst (wie soll der Benutzer erfahren, welche Typen es gibt? Über Strings?
std::type_info? Sonstige IDs?)// Abstrakte Basisklasse für gemeinsames Ansprechen class BaseType { public: virtual ~BaseType(); // Deine abstrakte Schnittstelle private: // ... }; // Klasse, die statische Typinformation hat und diese in // ihren virtuellen Funktionen benutzt template <typename ConcreteType> class DerivedType : public BaseType { // ... };Registrieren kannst du die Typen z.B. in einem
boost::ptr_vector<BaseType>. Übrigens implementiertboost::anymehr oder weniger genau sowas wieBaseType.
-
Ach das meinst du. Benutze ich die ganze Zeit, wusste nur nicht, dass es so heißt

Das geht natürlich, solange die IDs eben Objekte und nicht Typen sind.
Im jetzt gewählten Modell müsste man die Typen in einer Typliste registrieren. Was böte sich dafür an?
Philipp