Strikte Typdefinition
-
Hallo,
mir ist folgendes aufgefallen:
typedef int my_int;
Ich kann my_int überall dort übergeben, wo ein int erwartet wird. Gibt es eine Möglichkeit dass zu unterbinden? Ich würde gerne,dass ich nicht um einen cast herumkomme.
Danke euch!

Bye, donnerCobra
-
typedeferstellt nur ein Synonym. Der Typ bleibt gleich. Wenn du einen neuen Typ willst, dann kommst du umclassoderstructnicht herum.Grüssli
-
Dafür nutze ich immer eine Wrapper-Klasse:
template<typename T> class wrapper { public: explicit wrapper(T t) : _t(t) {} operator T() const { return _t; } private: T _t; };Benutzung dann so:
typedef wrapper<int> my_int; my_int x = my_int(42); // int y = x;Wenn du letzteres unterbinden willst, dann einfach den Operator entfernen und dafür dann z.B. eine Methode "cast()" anbieten.
Wenn du jedoch Zuweisungen der Art
typedef int my_int; typedef int my_int2; my_int x; my_int2 y; x = y; // <-- dies unterbinden?verbieten willst (d.h. Compiler-Fehler), dann kann ich dir eine andere Klasse anbieten, die nur im TEST-Modus Fehler wirft (wenn du obige Wrapper-Klasse nicht verwenden willst).
-
Super, vielen Dank!
Zur Wrapperklasse: ist dies aufgrund des Wrappers (ok, ein bisschen Overhead) langsamer als der reine Datentyp?
@ Th69 Wenn du mir die eine Klasse zur Verfügung stellen könntest, wäre das super.
Bye, donnerCobra
-
Nein, das sollte im Release-Mode eigentlich alles inline ausgeführt werden (ist also nur syntaktischer Overhead).
Und hier noch meine Header-Datei 'type.h' mit der Klasse 'type':
#ifndef TYPE_H #define TYPE_H #ifdef TEST_TYPE template<typename T, class NAME> class type { public: typedef type<T, NAME> THIS; type() {} type(const THIS& t) { x = t.x; } type(const T& _t) { x = _t; } // operator T() const { return x; } T value() const { return x; } template<class U> U cast() const { return (U)x; } THIS& operator = (const THIS& t) { x = t.x; return *this; } THIS& operator *= (const THIS& t) { x *= t.x; return *this; } THIS& operator /= (const THIS& t) { x /= t.x; return *this; } THIS& operator %= (const THIS& t) { x %= t.x; return *this; } THIS& operator += (const THIS& t) { x += t.x; return *this; } THIS& operator -= (const THIS& t) { x -= t.x; return *this; } THIS& operator <<=(const THIS& t) { x <<= t.x; return *this; } THIS& operator >>=(const THIS& t) { x >>= t.x; return *this; } THIS& operator &= (const THIS& t) { x &= t.x; return *this; } THIS& operator |= (const THIS& t) { x |= t.x; return *this; } THIS& operator ^= (const THIS& t) { x ~= t.x; return *this; } const THIS& operator ++ () { ++x; return *this; } const THIS& operator -- () { --x; return *this } THIS operator ++ (int) { THIS t = *this; ++x; return t; } THIS operator -- (int) { THIS t = *this; --x; return t; } bool operator ==(const THIS& t) const { return x == t.x; } bool operator !=(const THIS& t) const { return x != t.x; } bool operator < (const THIS& t) const { return x < t.x; } bool operator <=(const THIS& t) const { return x <= t.x; } bool operator > (const THIS& t) const { return x > t.x; } bool operator >=(const THIS& t) const { return x >= t.x; } THIS operator * (const THIS& t) const { return THIS(x * t.x); } THIS operator / (const THIS& t) const { return THIS(x / t.x); } THIS operator % (const THIS& t) const { return THIS(x % t.x); } THIS operator + (const THIS& t) const { return THIS(x + t.x); } THIS operator - (const THIS& t) const { return THIS(x - t.x); } THIS operator <<(const THIS& t) const { return THIS(x << t.x); } THIS operator >>(const THIS& t) const { return THIS(x >> t.x); } THIS operator & (const THIS& t) const { return THIS(x & t.x); } THIS operator | (const THIS& t) const { return THIS(x | t.x); } THIS operator ^ (const THIS& t) const { return THIS(x ^ t.x); } THIS operator + () const { return THIS( x); } THIS operator - () const { return THIS(-x); } THIS operator ! () const { return THIS(!x); } THIS operator ~ () const { return THIS(~x); } friend bool operator ==(const T& _t, const THIS& t) { return _t == t.x; } friend bool operator !=(const T& _t, const THIS& t) { return _t != t.x; } friend bool operator < (const T& _t, const THIS& t) { return _t < t.x; } friend bool operator <=(const T& _t, const THIS& t) { return _t <= t.x; } friend bool operator > (const T& _t, const THIS& t) { return _t > t.x; } friend bool operator >=(const T& _t, const THIS& t) { return _t >= t.x; } friend THIS operator * (const T& _t, const THIS& t) { return THIS(_t * t.x); } friend THIS operator / (const T& _t, const THIS& t) { return THIS(_t / t.x); } friend THIS operator % (const T& _t, const THIS& t) { return THIS(_t % t.x); } friend THIS operator + (const T& _t, const THIS& t) { return THIS(_t + t.x); } friend THIS operator - (const T& _t, const THIS& t) { return THIS(_t - t.x); } friend THIS operator <<(const T& _t, const THIS& t) { return THIS(_t << t.x); } friend THIS operator >>(const T& _t, const THIS& t) { return THIS(_t >> t.x); } friend THIS operator & (const T& _t, const THIS& t) { return THIS(_t & t.x); } friend THIS operator | (const T& _t, const THIS& t) { return THIS(_t | t.x); } friend THIS operator ^ (const T& _t, const THIS& t) { return THIS(_t ^ t.x); } private: T x; }; #define TYPEDEF(T, NAME)\ struct _S_##NAME\ {\ static const char * const name() { return #NAME; }\ };\ typedef type<T, _S_##NAME> NAME;\ /* partial template */\ template<class U> U CAST(const NAME& t)\ {\ return U(t.value()); /* t.template cast<U>(); */\ } #else #define TYPEDEF(T, NAME)\ typedef T NAME; template<class U, class T> U CAST(const T& t) { return U(t); }; #endif #endifDamit kannst du verschiedene typedefs voneinander trennen, obwohl sie auf demselben Datentyp beruhen.
Hier meine Testfunktion dazu:#define TEST_TYPE #include "type.h" TYPEDEF(int, ID); TYPEDEF(int, INDEX); static INDEX st_idx[] = { 0, 10, 5, 3, 2, 1 }; void test_type() { ID id = 42; INDEX index = 101; INDEX index2 = st_idx[0]; id *= 4; id = 10 - id; ID id2 = id++; id = -id2; id2 -= id; id = 2 * (id2 + 5); if(id2 != 0) id2 = -1; if(0 > id2) id2 = id - 100; if(id == id2) ++id2; ID *pId = &id; *pId = 5; id2 = *pId; // errors! --> good! /* id = index; id *= index; ID id3 = index; ID id4(index); if(id == index) index = 5 + id; */ // with explicit casting --> OK if(CAST<INDEX>(id) == index) id += CAST<ID>(index); int i = CAST<int>(id); i = i; unsigned short us = CAST<unsigned short>(id); us = us; }Du brauchst dann einfach z.B. im Debug-Modus das '#define TEST_TYPE' aktivieren - und im Release-Mode dann normal kompilieren (um nicht den unnötigen Overhead der internen Klasseninstanzen für das template 'class <...> type' zu haben.
Du mußt dazu dann allerdings statttypedef int my_int;dann immer das define
TYPEDEF(int, my_int);benutzen.
-
selbst mittels präprozessor könnte man das hübscher machen... die richtige wahl wäre hier aber(wie der name des makros schon sagt :P) ein einfaches typedef...
den name halte ich für sinnlos.../* wrapper.h */ namespace detail { template<typename T> struct foo { /*...*/ }; } #if defined(NDEBUG) template<typename T> struct wrapper { typedef detail::foo<T> type; }; #else template<typename T> struct wrapper { typedef T type; }; #endifoder aber
/* wrapper.h */ template<typename T> struct wrapper { /*...*/ # if defined(NDEBUG) typedef wrapper type; # else typedef T type; # endif };in beiden fällen würde das so einfach und intuitiv zu nutzen gehen:
/* main.cpp */ typedef wrapper<int>::type id_t; int main() { id_t id(100); }zurück zu deinem code:
typedef type<T, NAME> THIS;
1. ist THIS nen doofer name für nen typen - wenn überhauptthis_typeoder so.
2. ist die explizite angabe der template-argumente gar nicht nötig. ein einfachestypedef type this_type;würde da reichen.const T& _t, const THIS& t
wieso nicht lhs und rhs, wie das jeder macht sondern ein _t und t? Oowenn die typtrennung strikt sein soll, wieso dann
// operator T() const { return x; }?
dann schreib doch im private-teil einfach nochoperator T() const;template<class U> U cast() const { return (U)x; }
hier sollte man aber echt mit c++ casts arbeitenich nehm mal an, dass es einen grund gibt, wieso man alle operatoren als friend und nicht friend implementiert, obwohl man eh nicht
id.operator==(other_id)schreiben kann, gibt!?THIS operator + () const { return THIS( x); }
das hier ist aber echt faileigtl würd ich alle operatoren als template anbieten...
die streaming-operatoren hast du auch nicht überladen...bb
-
Hallo unskilled,
bei meiner 'type.h' geht es darum, daß z.B. zwei typedef-ints eben nicht als gleich gelten sollen, d.h. bei deinem Wrapper ist
typedef wrapper<int>::type id_t; typedef wrapper<int>::type index_t; int main() { id_t id(100); index_t index(42); id = index; // <-- kein Compiler-Fehler! }möglich, und bei meiner Type-Klasse eben nicht!
Und bzgl. meines Codes:
diesen habe ich vor ca. 7 Jahren auf einem älteren MSVC compilieren müssen, daher auch einige unschöne Dinge...Meine eigentliche 'type.h' sieht heute auch etwas anders aus...
Aber du darfst sie gerne nach deinen Wünschen aufpolieren und bei boost einreichen -)
-
Th69 schrieb:
Hallo unskilled,
bei meiner 'type.h' geht es darum, daß z.B. zwei typedef-ints eben nicht als gleich gelten sollen, d.h. bei deinem Wrapper ist
das hatte ich schon verstanden

myself schrieb:
wenn die typtrennung strikt sein soll, wieso dann // operator T() const { return x; } ?
dann schreib doch im private-teil einfach noch operator T() const;;o)
bb
-
Welchen Zweck soll denn der Datentyp haben, vielleicht ist es ja mit einer einfachen enum auch getan?