marcolo2307 Temat założony przez niniejszego użytkownika |
Tablica przechowująca wiele typów » 2017-04-02 14:02:56 Cześć! Zastanawiam się jak zrobić mapę, która będzie mogła trzymać dane każdego typu. Chcę uniknąć tworzenia własnych klas poprzez dziedziczenie z jakiejś wspólnej bazowej. Czytałem o Boost::Any, ale jakoś mnie do siebie nie przekonuje... Szukam innego rozwiązania. Czytałem też o decltype, czy jest możliwe rozwiązanie w stylu: std::map < std::string, decltype > ? Wtedy w drugiej mapie można by przechowywać wskaźnik void* i rzutować. Jedynym problemem przy void* jest delete. Aby usunąć wskaźnik muszę w jakiś sposób określić typ. Moim celem jest zrobienie mniej więcej takiej klasy: class Config { public: Config(); Config(); bool loadFromFile( std::string filename ); void add( std::string name, void * data ); template < class T > add( std::string name, T * data ); void remove( std::string name ); private: std::map < std::string, void *> m_Map; }; Nawet jeśli zrezygnuję z możliwości usuwania danych to wciąż muszę usunąć je w destruktorze klasy. Tutaj wrzucam klasę, którą napisałem wcześniej: class ConfigData { private: struct ConfigInfo { void * m_Config; unsigned int m_Size; }; public: ConfigData(); virtual ~ConfigData(); virtual void reset() = 0; void save( std::string filename ); bool load( std::string filename ); void add( std::string name, void * data, size_t size ) { if( name.size() > 128 ) throw Exception( "Too long name for config option! (\"" + name + "\")" ); ConfigInfo ci; ci.m_Config = data; ci.m_Size = size; m_Config.insert( std::pair < std::string, ConfigInfo >( name, ci ) ); } template < class T > const T & get( std::string name ) const { auto it = m_Config.find( name ); if( it == m_Config.end() ) throw Exception( "Failed to find a setting: \"" + name + "\"!" ); return * reinterpret_cast < T *>( it->second.m_Config ); } template < class T > void set( std::string name, T value ) { auto it = m_Config.find( name ); if( it == m_Config.end() ) throw Exception( "Failed to find a setting: \"" + name + "\"!" ); T * config = reinterpret_cast < T *>( it->second.m_Config ); * config = value; } protected: std::map < std::string, ConfigInfo > m_Config; }; |
|
Bielan |
» 2017-04-02 15:49:11 |
|
mateczek |
» 2017-04-02 16:07:50 w prosty sposób tego nie załatwisz. w Qt jest qVariant ale wygodne tylko dla typów Qt. Z własnymi typami jest trochę zabawa. Bo przecież w obiekcie musi być info na temat typu. kiedyś klepnąłem takie info o tym jak dodać własny typ do qVariant. Ale wydaje mi się to średnio wygodne https://pl.wikibooks.org/wiki/Programowanie_C%2B%2B_Qt4_w_systemie_Gnu-Linux/QVariant#include "plcBitsArray.h" #include <QDebug> #include<QVariant>
int main() { QVariantList blok = { QVariant::fromValue( plcBitsArray( 0 ) ), QVariant::fromValue( WORD( 0 ) ), QVariant::fromValue( int( 0 ) ) }; foreach( const QVariant & zm, blok ) { qDebug() << zm.typeName(); } qDebug() << blok[ 0 ].value < plcBitsArray >()[ 1 ] << " -pierwszy element tablicy bitowej"; }
|
|
marcolo2307 Temat założony przez niniejszego użytkownika |
» 2017-04-02 17:28:29 Próbuję z boost::any, ale nie mam pojęcia jak to zapisać i odczytać z pliku ;/ |
|
mokrowski |
» 2017-04-02 18:04:01 Raczej nie interesuje Cię Boost.Any tylko Boost.Variant http://www.boost.org/doc/libs/1_61_0/doc/html/variant.html . Chodzi Ci przecież o ograniczony zestaw typów.
Co do wczytywania z pliku, wyjścia masz 2: 1. Zapisanie znacznika o typie danych w pliku 2. Próbować rzutowania na typ docelowy i zapisanie go do kontenera jak rzutowanie się udało.
W C++17 ma być dostępny typ variant http://en.cppreference.com/w/cpp/utility/variant . Sprawdź w swoim kompilatorze czy już go nie masz w <experimental/variant>. |
|
marcolo2307 Temat założony przez niniejszego użytkownika |
» 2017-04-02 18:10:32 To nie ma być ograniczony zestaw typów. Ma to być klasa przechowująca wszystkie potrzebne dane. Część jest stała, ładowana z pliku, inne są tworzone dynamicznie. Chcę aby można było zapisywać absolutnie wszystko.
Czy może lepiej zmienić koncepcję i zapisywać tylko określone typy? Teoretycznie mogę trzymać wszystko w stringach, przy wbudowanych typach to nie będzie problem, ale np. przy wektorach już owszem. Chcę uniknąć konieczności tworzenia własnych funkcji/operatorów tylko dlatego, żeby móc coś przechować w tej klasie. |
|
Bielan |
» 2017-04-02 19:50:37 Po Twoim ostatnim temacie wnoszę, że wcale nie chodzi ci o mapę z dowolnym typem ale o możliwość zapisu dowolnej klasy do pliku? |
|
marcolo2307 Temat założony przez niniejszego użytkownika |
» 2017-04-02 20:20:00 Ostatnie tematy nie mają związku z niczym, z powodu szkoły miałem długą przerwę od programowania. Jedyne co mi pozostało to zamiłowanie do pisania wszelkiego rodzaju silników i frameworków :P
Chcę zapisu także wbudowanych typów: int, bool itd. Do tego np. std::string czy sf::Vector2f.
Chodzi mi o to, żebym mógł przechować sobie wszystkie potrzebne informacje w jednym pliku i ładować je do jednej klasy bez ograniczania się do konkretnych typów - nie jestem w stanie przewidzieć wszystkich, dlatego najłatwiej byłoby trzymać je jako void* i rzutować według template podanego przez użytkownika. Wcześniej po prostu dziedziczyłem po abstrakcyjnej klasie i za każdym razem pisałem własny sposób zapisu, gdzie znałem typy, ale teraz chcę stworzyć coś uniwersalnego.
Założenie jest takie, że mogę dodać, zapisać i pobrać każdy typ danych za pomocą pojedynczych metod, tak aby były gotowe do pracy, czyli np. get<T> czy add(void*)/add(T)
Od jakiegoś tygodnia nie potrafię pokonać bariery zapisu do pliku.
Zapis dowolnej klasy nie jest problemem, to potrafię zrobić z samym fstream::write i sizeof(class).
W zasadzie wystarczyłoby mi coś, co pozwoli mi bezpiecznie usunąć void* - tak byłoby najprościej. No ale typeinfo mi tu nie pomoże, bo aby rzutować musiałbym pisać switcha, a to ograniczy mnie do konkretnych typów. decltype nie jestem w stanie zapisać w żadnej zmiennej, więc też z niego nie skorzystam. |
|
« 1 » 2 |