Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Tablica przechowująca wiele typów

Ostatnio zmodyfikowano 2017-04-02 22:08
Autor Wiadomość
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:
C/C++
class Config
{
public:
    Config();
    Config();
   
    bool loadFromFile( std::string filename ); // ladowanie z pliku nie pozwala na uzycie szablonu calej klasy - jedynie metody add
   
    void add( std::string name, void * data /*, decltype() lub cos innego? */ ); // ewentualnie
    template < class T > add( std::string name, T * data ); // ale wtedy i tak calosc musze przechowywac w mapie void* - pozwala mi to jedynie na bezposrednie zdobycie typu, ale nie wiem jak go zapisac
   
    void remove( std::string name ); // usuwa dane poprzez delete - nie moge usunac wskaznika void*
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:

C/C++
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;
};
P-159694
Bielan
» 2017-04-02 15:49:11
http://www.boost.org/doc/libs​/1_47_0/doc/html/any.html
Frazy, które należy wpisać w wyszukiwarkę google:

P-159698
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_sy​stemie_Gnu-Linux​/QVariant
C/C++
#include "plcBitsArray.h" // moja klasa
#include <QDebug>
#include<QVariant>


int main()
{
    QVariantList blok = { QVariant::fromValue( plcBitsArray( 0 ) ), QVariant::fromValue( WORD( 0 ) ), QVariant::fromValue( int( 0 ) ) }; // kontener z różnymi typami
    //QList<QVariant>block jest równoznaczne z QVariantList blok;
    //blok to kontener który zawiera 3 elementy
    foreach( const QVariant & zm, blok ) {
        qDebug() << zm.typeName(); // wyświetlanie na konsole jaki typ siedzi w kontenerze
    }
    //wypisanie bitu 1 na konsole z kontenera blok;
    qDebug() << blok[ 0 ].value < plcBitsArray >()[ 1 ] << " -pierwszy element tablicy bitowej";
   
}
P-159699
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 ;/
P-159701
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>.
P-159703
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.
P-159705
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?
P-159708
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.
P-159719
« 1 » 2
  Strona 1 z 2 Następna strona