| Uutiset | Koodikirjasto | Wiki | Keskustelut | FAQ | Info |
CAnyContainergummikana 30.01.04 19:08 Template viritelmä, jonka avulla voi tehdä stl:än containereista tyypittömiä. Pilkottu versio löytyy täältä: http://koti.mbnet.fi/kumikana/soodaus/cpp/CAnyContainer/canycontainer.zip
//////////////////////////////////////////////////////////////// // CAnyContainer //-------------------------------------------------------------- // // Lyhyesti CAnyContainer on luokka, jonka avulla voi muuttaa // STL:än containerit tyypittömiksi, eli niin, että ne hyväksyvät // minkä tahansa tyyppisiä muuttujia. Alhaalta löytyy kattava // esimerkki CAnyContainerin käytöstä. // // Tämä tiedosto on kolmen tiedoston yhdistelmä, joka toimii // sellaisenaan, mutta jos oikeasti haluat käyttää // CAnyContaineria kannattaa nämä tiedostot pilkkoa sopiviin // header tiedostoihin. // // Pilkottu versio löytyy täältä: // http://koti.mbnet.fi/kumikana/soodaus/cpp/CAnyContainer/canycontainer.zip // // täällä voi ihailla koodia: // http://koti.mbnet.fi/kumikana/soodaus/cpp/CAnyContainer/ // // // CAnyContainer käyttää CVarReference luokka kokoelmaa, josta // olen suhteellisen ylpeä, sillä se on osoittautunut paljon // hyödyllisemmäksi ja monikäyttöisemmäksi kuin osasin ikinä // kuvitella. Toinen applikaatio missä olen tätä luokka // kokoelmaa käyttänyt on CConsole luokka ( siis sen uusin // versio ). CConsole löytynee täältä: // http://koti.mbnet.fi/kumikana/soodaus/cpp/CConsole/ // //-------------------------------------------------------------- // Begin of cvarreference.h #ifndef INC_CVARREFERENCE_H #define INC_CVARREFERENCE_H //////////////////////////////////////////////////////////////// // // cvarreference.h // // Writen 11.01.2004 // by Petri Purho ( pete@markkupurho.fi ) // // Basicly this is set of classes derived from CVarRefBase class // used to set values to "any" class. If you want to add your // own class to the supported classes write a new function // to the cengstringstream class. // //////////////////////////////////////////////////////////////// #include <typeinfo> #include <string> #include <sstream> //////////////////////////////////////////////////////////////// namespace std { // This class here is used to setting values to the types... // class cengstringstream : public istringstream { public: cengstringstream( openmode mode = in ) : istringstream( mode ), myStr("") { } cengstringstream( const string& str, openmode mode = in ) : istringstream( str, mode ), myStr( str ) { } //istream& operator>> ( int& val ) { return istringstream::operator>>(val); } template< typename _T > istream& operator>> ( const _T& val ) const { return *this; } template< typename _T > istream& operator>> ( _T& val ) { return *this; } istream& operator>> (bool& val ) { return istringstream::operator>>(val); } istream& operator>> (short& val ) { return istringstream::operator>>(val); } istream& operator>> (unsigned short& val ) { return istringstream::operator>>(val); } istream& operator>> (int& val ) { return istringstream::operator>>(val); } istream& operator>> (unsigned int& val ) { return istringstream::operator>>(val); } istream& operator>> (long& val ) { return istringstream::operator>>(val); } istream& operator>> (unsigned long& val ) { return istringstream::operator>>(val); } istream& operator>> (float& val ) { return istringstream::operator>>(val); } istream& operator>> (double& val ) { return istringstream::operator>>(val); } istream& operator>> (long double& val ) { return istringstream::operator>>(val); } istream& operator>> (void*& val ) { return istringstream::operator>>(val); } istream& operator>> (string& sb ) { sb = myStr; return (*this); } private: const string& myStr; }; } //////////////////////////////////////////////////////////////// // The idea of CVarRef classes is that you can create a // reference to any variable. Be it const or nor. And you can // change that variables value by a string value. Very handy // in lots of places. Like the CAnyContainer // // The CVarRefBase is a abstract class, that defines the interface class CVarRefBase { public: CVarRefBase() { } virtual ~CVarRefBase() { } virtual void SetValue( const std::string& value ) = 0; virtual std::string GetValue() const = 0; virtual std::string GetName() const = 0; virtual std::string GetType() const = 0; virtual bool GetConst() const = 0; }; //////////////////////////////////////////////////////////////// // This is a the basic reference, that actually does something template< typename _Ty > class CVarRef : public CVarRefBase { public: CVarRef( const std::string& varname, _Ty& var ) : myVariable( var ), myVariableName( varname ), myVariableType( typeid( var ).name() ), myConst( false ) { } void SetValue( const std::string& value ) { if ( !myConst ) std::cengstringstream( value ) >> myVariable; } std::string GetValue() const { std::stringstream ss; ss << myVariable; return ss.str(); } std::string GetName() const { return myVariableName; } std::string GetType() const { return myVariableType; } bool GetConst() const { return myConst; } private: _Ty& myVariable; std::string myVariableName; std::string myVariableType; bool myConst; }; //////////////////////////////////////////////////////////////// // This a handy helper class, when sometimes you need to create // a variable and a reference to it. This actually fakes the // reference and stores the variable in it self. template< typename _Ty = std::string > class CVarRefEmpty : public CVarRefBase { public: CVarRefEmpty( const std::string& varname, bool isconst = false ) : myVariable(), myVariableName( varname ), myVariableType( typeid( _Ty ).name() ), myConst( isconst ) { } void SetValue( const std::string& value ) { if ( !myConst ) std::cengstringstream( value ) >> myVariable; } std::string GetValue() const { std::stringstream ss; ss << myVariable; return ss.str(); } std::string GetName() const { return myVariableName; } std::string GetType() const { return myVariableType; } bool GetConst() const { return myConst; } private: _Ty myVariable; std::string myVariableName; std::string myVariableType; bool myConst; }; //////////////////////////////////////////////////////////////// // This another helper class used when you encounter a const // class template< typename _Ty > class CVarRefConst : public CVarRefBase { public: CVarRefConst( const std::string& varname, const _Ty& var ) : myVariable( var ), myVariableName( varname ), myVariableType( typeid( var ).name() ), myConst( true ) { } void SetValue( const std::string& value ) { } std::string GetValue() const { std::stringstream ss; ss << myVariable; return ss.str(); } std::string GetName() const { return myVariableName; } std::string GetType() const { return myVariableType; } bool GetConst() const { return myConst; } private: const _Ty& myVariable; std::string myVariableName; std::string myVariableType; bool myConst; }; //////////////////////////////////////////////////////////////// #endif // end of cvarreference.h // begin of canycontainer.h #ifndef INC_CANYCONTAINER_H #define INC_CANYCONTAINER_H //////////////////////////////////////////////////////////////// // // CAnyContainer.h // // Writen 30.01.2004 // by Petri Purho ( pete@markkupurho.fi ) // // A basic container used with stl containers to make them type // free containers. You don't have to worry about the template // coding, you just declare a stl container with CAnyContainer // type and you can push there variables of any type. // // example: /* std::vector< CAnyContainer > myVector; myVector.push_back( 1 ); // integer myVector.push_back( std::string( "stringvalue" ); myVector.push_back( 1.5 ); // double myVector[ 0 ] = std::string( "string" ); */ // To get the values you can use CAnyContainerCast function // or GetValue method. GetValue() returns the value as a string. // //////////////////////////////////////////////////////////////// #include <string> #include <sstream> #include <list> #include <algorithm> // #include "cvarreference.h" //////////////////////////////////////////////////////////////// // This here is a basic set of containers, which stores // variables of any type. class CContainerBase { public: CContainerBase() { } virtual ~CContainerBase() { } }; //////////////////////////////////////////////////////////////// template< class _Ty > class CContainer : public CContainerBase { public: CContainer( const _Ty& ref ) : myVar( ref ) { } ~CContainer() { } _Ty myVar; }; //////////////////////////////////////////////////////////////// class CAnyContainer { public: CAnyContainer() : myContainer( NULL ), myReference( NULL ) { AddBan( this ); } template < class _Ty > CAnyContainer( const _Ty& reference ) : myContainer( NULL ), myReference( NULL ) { if ( IsBanned( this ) == false ) { delete myContainer; delete myReference; } else RemoveBan( this ); CContainer<_Ty>* tmp_ptr = new CContainer< _Ty >( reference ); myReference = new CVarRefConst<_Ty>( "", tmp_ptr->myVar ); myContainer = tmp_ptr; } template<> CAnyContainer( const CAnyContainer& other ) : myContainer( NULL ), myReference( NULL ) { if ( IsBanned( this ) == false ) { delete myContainer; delete myReference; } else RemoveBan( this ); other.BanMe(); myContainer = other.myContainer; myReference = other.myReference; } ~CAnyContainer() { if ( IsBanned( this ) == false ) { delete myContainer; delete myReference; } else RemoveBan( this ); } template< class _Ty > CAnyContainer& operator= ( const _Ty& reference ) { if ( IsBanned( this ) == false ) { delete myContainer; delete myReference; } else RemoveBan( this ); CContainer<_Ty>* tmp_ptr = new CContainer< _Ty >( reference ); myReference = new CVarRefConst<_Ty>( "", tmp_ptr->myVar ); myContainer = tmp_ptr; return *this; } std::string GetValue() const { return myReference->GetValue(); } template< class _Ty > std::string GetValue( _Ty& var ) const { std::cengstringstream( GetValue() ) >> var; return GetValue(); } private: void BanMe() const { AddBan( this ); } void AddBan( const CAnyContainer* banme ) const { if ( IsBanned( banme ) ) return; myDeleteBanList.push_back( banme ); } void RemoveBan( const CAnyContainer* banned ) { if ( IsBanned( banned ) == false ) return; myDeleteBanList.remove( banned ); } bool IsBanned( const CAnyContainer* ban ) const { std::list< const CAnyContainer* >::iterator i; i = std::find( myDeleteBanList.begin(), myDeleteBanList.end(), ban ); return ( i != myDeleteBanList.end() ); } CContainerBase* myContainer; CVarRefBase* myReference; static std::list< const CAnyContainer* > myDeleteBanList; }; std::list< const CAnyContainer* > CAnyContainer::myDeleteBanList; //////////////////////////////////////////////////////////////// std::ostream& operator << ( std::ostream& os, CAnyContainer& container ) { os << container.GetValue(); return os; } //////////////////////////////////////////////////////////////// template< class _Ty > _Ty CAnyContainerCast( const CAnyContainer& container ) { _Ty tmp_var; container.GetValue( tmp_var ); return tmp_var; } //////////////////////////////////////////////////////////////// #endif // end of canycontainer.h // begin of main.cpp #include <iostream> #include <vector> #include <string> // #include "canycontainer.h" int main() { // Ensin teet stl containerin joka käyttää CAnyContaineria // tyyliin: std::vector< CAnyContainer > myVector; // Sen jälkeen voit survoa minkä tahansa tyyppistä tavaraa // tuhon stl containeriin. myVector.push_back( 10 ); myVector.push_back( 10.5 ); myVector.push_back( std::string( "tekstiä" ) ); // Tekstin kanssa, siis tarkemmin merkkijonojen kanssa // joutuu vähän kikkaamaan ja käyttämään std::stringiä // koska templatet eivät tykkää merkkijonoista, koska // char[20] on eri tyyppinen muuttuja kuin char[19]. // Tämä aiheuttaa epämiellyttäviä ongelmia jotka pystyy // kiertämään käyttämällä std::stringiä. // Voit myös muuttaa näitä suoraan, tyyliin myVector[ 0 ] = std::string( "muutettiin tekstiksi" ); std::cout << myVector[ 0 ] << std::endl; // tulostaa: muutettiin tekstiksi std::cout << myVector[ 1 ] << std::endl; // tulostaa: 10.5 // muuttujien arvoja saa GetValue metodilla. // Joka defaulttina palauttaa muuttujan arvon std::string // tyyppisenä std::string string_muuttuja = myVector[ 0 ].GetValue(); // Muun tyyppisiä muuttujia saat ulos joko, GetValue( muuttuja ) // metodilla tai CAnyContainerCast<> funktiolla. double double_muuttuja; myVector[ 1 ].GetValue( double_muuttuja ); std::cout << double_muuttuja << std::endl; // tulostaa: 10.5 myVector[ 1 ] = 20.5; double_muuttuja = CAnyContainerCast< double >( myVector[ 1 ] ); std::cout << double_muuttuja << std::endl; // tulostaa: 20.5 return 0; } // end of main.cpp |
![]() Haku
|