Datentyp/Aufzählungstyp für den Wertebereich von 5 bis 5000 definieren
-
Hallo zusammen,
mich interessiert welche Möglichkeiten bestehen im C++ einen Datentyp zwischen 5 und 5000 zu erzeugen?
Man könnte ja versuchen mit enum den Bereich zu definieren, das sieht mir aber nach verdammt viel Schreibarbeit aus. Eine elegante Möglichkeit gibt es bestimmt und ich wäre Ihnen sehr dankbar für einen Hinweis.Unter Delphi würde ich das so definieren:
**
Type
TZahl = set of 5..5000;
**
*
Mit freundlichen Grüßen
Coder24h
*
-
Dieser Thread wurde von Moderator/in Jansen aus dem Forum Borland C++ Builder (VCL/CLX) in das Forum C++ verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
Ne, meines Wissens nach dürfte das nicht gehen...
Aber du könntest ja nen wrapper um unsigned short schreiben...:
template<std::size_t min,std::size_t max,class Type_to_use> //Type_to_use sollte man auch ermitteln können, siehe unten... class m_type { private: Type_to_use t; void control_and_set() { if(t<min) { t=max-t; //eventuell willst du ein underflow-bit setzen return; } else if(t>max) t=min+(t-max); //overflow-bit? }; public: };
Du überlädst einfach alle operatoren und rufst nach jeder Veränderung control_and_set() auf.
Type selbst ermitteln:namespace help { template<class T> struct my_limits; //hier my_limits überladen (climits benutzen) template<bool unsigned_,std::size_t min,std::size_t max,Loki::TypeList Typesu,Loki::TypeList Typess> struct h { private: enum{passt_rein=my_limits<head>::min<=min&&my_limits<head>::max>=max}; public: enum{min_diff=passt_rein?min-my_limits<head>::min:my_limits<int>::max, max_diff=passt_rein?my_limits<head>::max-max:my_limits<int>::max}; typedef typename Typesu::Head head; }; template<bool unsigned_,std::size_t min,std::size_t max,Loki::TypeList Typess> struct h<unsigned_,min,max,Loki::NullType,Typess> { enum{min_diff=m_limits<int>::max,max_diff=m_limits<int>::max}; typedef Loki::NullType head; }; template<std::size_t min,std::size_t max,Loki::TypeList Typess> struct h<false,min,max,Loki::NullType,Typess> { enum{min_diff=m_limits<int>::max,max_diff=m_limits<int>::max}; typedef Loki::NullType head; }; template<std::size_t min,std::size_t max,Loki::TypeList Typesu,Loki::TypeList Typess> struct h<false,min,max,Typesu,Typess> { private: enum{passt_rein=my_limits<head>::min<=min&&my_limits<head>::max>=max}; public: enum{min_diff=passt_rein?min-my_limits<head>::min:my_limits<int>::max, max_diff=passt_rein?my_limits<head>::max-max:my_limits<int>::max}; typedef typename Typess::Head head; }; template<bool unsigned_,std::size_t min,std::size_t max,Loki::TypeList Typesu,Loki::TypeList Typess> struct g { private: typedef g<min,max,typename Typesu::Tail,typename Typess::Tail> next; typedef typename h<unsigned_,min,max,Typesu,Typess>::head type; enum{min_diff=h<unsigned_,min,max,Typesu,Typess>::min_diff, max_diff=h<unsigned_,min,max,Typesu,Typess>::max_diff}; enum{passt_rein=min_diff!=m_limits<int>::max&&min_diff!!=m_limits<int>::max}; public: enum{gibt_wert=passt_rein||next::gibt_wert}; enum{diff=min_diff+max_diff}; typedef typename Loki::Select<gibt_wert,typename Loki::Select<passt_rein&&g::gibt_wert,typename Loki::Select<(diff<next::diff),type,next::result>::Result,typename Loki::Select<passt_rein,type,typename next::result>::Result,Loki::NullType>::Result result; }; } template<std::size_t min,std::size_t max> struct get_type { STATIC_CHECK(min<max); typedef typename help::g<(min<=0),min,max,TYPELIST_4(unsigned char,unsigned short,unsigned,unsigned long),TYPELIST_4(char,short,int,long)>::result type; };
-
Hi ness,
ist natürlich schade wenn das auf die schnelle nicht geht. Es ist aber auch so, dass meine Kenntnisse in Sache C++ nicht gerade überragend sind und ich eine weile brauchen werde um das hier zu verstehen.
Dankeschön erstmal wobei ich natürlich für weitere Vorschläge offen bin.
*
Mit freundlichen Grüßen
Coder24h
*
-
Brauchst du unbedingt nen neuen Datentyp oder tuts auch ne normale Abfrage an einigen Stellen?
-
Hier mal eine (hoffentlich) funktionsfähige Klasse.
#include <iostream> namespace m_type { template<std::size_t min,std::size_t max,class R> class m_type { private: R t; bool overflow,underflow; Type_to_use t; void control_and_set() { if(t<min) { t=max-t; //eventuell willst du ein underflow-bit setzen underflow=true; return; } else if(t>max) { t=min+(t-max); //overflow-bit? overflow=true; }; }; public: m_type():t(0),overflow(false),underflow(false){}; m_type(R s):t(s),overflow(false),underflow(false){control_and_set():}; bool is_overflowed()const{return overflow;}; bool is_underflowed()const{return underflow;}; void clear_overflow(){overflow=false;}; void clear_underflow(){underflow=false}; void clear_stat(){underflow=false;overfow=false}; R get(){return t;}; void set(R r){t=r}; const m_type& operator=(const m_type& l){t=l.t;overflow=l.overflow;underflow=l.underflow; return *this;}; const m_type& operator+=(const m_type& l){t-=l.t;control_and_set();return *this;}; const m_type& operator-=(const m_type& l){t-=l.t;control_and_set();return *this;}; const m_type& operator*=(const m_type& l){t*=l.t;control_and_set();return *this;}; const m_type& operator/=(const m_type& l){t/=l.t;control_and_set();return *this;}; const m_type& operator+=(R l){t-=l;control_and_set();return *this;}; const m_type& operator-=(R l){t-=l;control_and_set();return *this;}; const m_type& operator*=(R l){t*=l;control_and_set();return *this;}; const m_type& operator/=(R l){t/=l;control_and_set();return *this;}; std::ostream& inner_op_out(std::ostream& o) { o<<t; return o; }; std::istream& inner_op_in(std::istream& i) { i>>t; return i; }; }; namespace std_out { template<std::size_t min,std::size_t max,class R> inline std::ostream& operator<<(std::ostream& o,const m_type<min,max,R>& m) { m.inner_op_out(o); }; }; namespace std_in { template<std::size_t min,std::size_t max,class R> inline std::istream& operator>>(std::istream& i,const m_type<min,max,R>& m) { m.inner_op_in(i); }; }; namespace math_ops { template<std::size_t min,std::size_t max,class R> inline const m_type<min,max,R> operator+(const m_type<min,max,R>& l,const m_type<min,max,R>& r) { return m_type<min,max,R>(l)+=r; }; template<std::size_t min,std::size_t max,class R> inline const m_type<min,max,R> operator+(const m_type<min,max,R>& l,R r) { return m_type<min,max,R>(l)+=r; }; template<std::size_t min,std::size_t max,class R> inline const m_type<min,max,R> operator+(R l,const m_type<min,max,R>& r) { return m_type<min,max,R>(l)+=r; }; template<std::size_t min,std::size_t max,class R> inline const m_type<min,max,R> operator-(const m_type<min,max,R>& l,const m_type<min,max,R>& r) { return m_type<min,max,R>(l)-=r; }; template<std::size_t min,std::size_t max,class R> inline const m_type<min,max,R> operator-(const m_type<min,max,R>& l,R r) { return m_type<min,max,R>(l)-=r; }; template<std::size_t min,std::size_t max,class R> inline const m_type<min,max,R> operator-(R l,const m_type<min,max,R>& r) { return m_type<min,max,R>(l)-=r; }; template<std::size_t min,std::size_t max,class R> inline const m_type<min,max,R> operator*(const m_type<min,max,R>& l,const m_type<min,max,R>& r) { return m_type<min,max,R>(l)*=r; }; template<std::size_t min,std::size_t max,class R> inline const m_type<min,max,R> operator*(const m_type<min,max,R>& l,R r) { return m_type<min,max,R>(l)*=r; }; template<std::size_t min,std::size_t max,class R> inline const m_type<min,max,R> operator*(R l,const m_type<min,max,R>& r) { return m_type<min,max,R>(l)*=r; }; template<std::size_t min,std::size_t max,class R> inline const m_type<min,max,R> operator/(const m_type<min,max,R>& l,const m_type<min,max,R>& r) { return m_type<min,max,R>(l)/=r; }; template<std::size_t min,std::size_t max,class R> inline const m_type<min,max,R> operator/(const m_type<min,max,R>& l,R r) { return m_type<min,max,R>(l)/=r; }; template<std::size_t min,std::size_t max,class R> inline const m_type<min,max,R> operator/(R l,const m_type<min,max,R>& r) { return m_type<min,max,R>(l)/=r; }; }; }; namespace std { template<std::size_t min,std::size_t max,class R> inline m_type<min,max,R> abs(m_type<min,max,R>& m) { return m_type(std::abs(m.get())); }; };
Ist jetzt nur so hier hingeschrieben, könnten also Flüchtigkeitsfehler sein. Wenns Probleme gibt, meld dich. Ich wills auch nicht verteufeln, aber ob das so sinnvoll ist?
/edit: hab die namespacers erst nachträglich hinzugefügt, desshalb ist das so wirr mit den KLammern...
-
Hi, also enums sollte man nach Möglichkeit so verwenden, dass man überhaupt gar nicht ihre Werte betrachtet. Enums sind nur verschiedene wohldefinierte Möglichkeiten, z.B. Rot, Gelb, Grün bei Farben. Wenn du den Zahlenwert brauchst, solltest du dir schon mal überlegen, ob enums das richtige sind. Ich will es nicht grundsätzlich verteufeln, aber man sollte es eher vermeiden.
-
coder24h schrieb:
ist natürlich schade wenn das auf die schnelle nicht geht. Es ist aber auch so, dass meine Kenntnisse in Sache C++ nicht gerade überragend sind
Das Problem ist einfach, dass C++ nicht direkt Wertebereiche definiert. Deshalb kannst du auch nicht einfach einen primitiven Typ diesbzgl. umdefinieren. Du hast dann eigentlich nur die Möglichkeit, sowas in einer Klasse zu kapseln. In boost gibts zB ein schönes Beispiel mit bool, da wird zu false und true noch ein indeterminate hinzugefügt. Das ganze nennt sich dann tri_bool.
Bevor man sowas macht, solltest du dich aber erst fragen, ob eine simple Abfrage des Wertebereiches an betreffender Stelle nicht einfacher wäre. Wie Michael E. halt schon sagte.
Wenn nicht, dann bleibt dir nichts anderes übrig, als eine spezielle Klasse zu machen. Wobei das nicht so kompliziert wie bei ness sein muss. Hier mal mein Vorschlag#include <cassert> template <class T, T Min, T Max> class limited_int { private: static const T& check(const T& source) { assert(source >= Min); // 1 assert(source <= Max); // 2 return source; } T value_; public: operator T() const { return value_; } limited_int(const T& source) : value_(check(source)) { } }; //... typedef limited_int<int, 5, 5000> my_int; my_int a = 1; // -> assert 1 my_int b = 10; // ok my_int c = 10000; // -> assert 2
Ist jetzt nur mal so mein erster Gedanke. Vielleicht hab ich aber auch noch was übersehen.
Zu beachten ist, dass dir noch sämtliche Assignment Operatoren fehlen (bis auf op= ). Die musst du dann halt bei Bedarf nachdefinieren, zBlimited_int& operator +=(const T& rhs) { value_ = check(value_ + rhs); return *this; }
Oder du schreibst dann immer die entsprechend lange Variante, zB
a = a + 100;
-
Ich bedanke mich bei Allen,
und ja bei mir kann ich das Ganze durch gezielte Abfragen umgehen! Es interessierte mich einfach ob eine solche Möglichkeit besteht oder nicht. Ich werde mich mit den beiden Beispielen näher beschäftigen wobei die letztere Variante übersichtlicher ist.
*
Vielen Dank
Coder24h
*