Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 13
  1. #1
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826

    [c++]type erasure, template

    ciao.
    Sto cercando di capire il type erasure , ma ho un qualche problema:

    codice:
    class Weapon {};
    class Armor {};
    class Helmet {};
    class Scroll {};
    class Potion {};
    
    class Object {
       struct ObjectConcept {
           virtual ~ObjectConcept() {}
       };
    
       template< typename T > struct ObjectModel : ObjectConcept {
           ObjectModel( const T& t ) : object( t ) {}
           virtual ~ObjectModel() {}
         private:
           T object;
       };
    
       boost::shared_ptr<ObjectConcept> object;
    
      public:
       template< typename T > Object( const T& obj ) :
          object( new ObjectModel<T>( obj ) ) {}
    };
    
    int main() {
       std::vector< Object > backpack;
    
       backpack.push_back( Object( Weapon( SWORD ) ) );
       backpack.push_back( Object( Armor( CHAIN_MAIL ) ) );
       backpack.push_back( Object( Potion( HEALING ) ) );
       backpack.push_back( Object( Scroll( SLEEP ) ) );
    }
    in virtu di cosa il tipo scompare?

    codice:
     template< typename T > Object( const T& obj ) :
          object( new ObjectModel<T>( obj ) ) {}
    questo costruttore non ha un tipo template?

    e allora come mai

    codice:
    backpack.push_back( Object( Weapon( SWORD ) ) );
    //non è
    backpack.push_back( Object<xxx>( Weapon( SWORD ) ) );
    in cosa è utilizzato principalmente il type erasure?
    ho visto un per esempio any di boost .
    grazie.

  2. #2
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381

    Re: [c++]type erasure, template

    Originariamente inviato da giuseppe500
    in virtu di cosa il tipo scompare?
    Scompare perché la classe Object non ha nessun riferimento all'oggetto che effettivamente manipola. Ha solo un generico riferimento a una classe ObjectConcept che funziona da astrazione a una classe derivata che effettivamente sa che cosa sta manipolando.
    Object poi dovrà usare i metodi virtuali generici messi a disposizione da ObjectConcept con cui operare sul dato reale.

    questo costruttore non ha un tipo template?
    e allora come mai

    codice:
    backpack.push_back( Object( Weapon( SWORD ) ) );
    //non è
    backpack.push_back( Object<xxx>( Weapon( SWORD ) ) );
    Non è Object a essere una classe template, ma ObjectModel. Il parametro template serve solo a quest'ultima classe.
    in cosa è utilizzato principalmente il type erasure?
    Serve per creare tipi di dati che si comportano in modo molto simile ai variant.
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  3. #3
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826
    grazie.

  4. #4
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826
    un altra cosa scusate:

    Ho un interfaccia base dove vorrei creare una funzione virtual che viene implementata da due classi concrete , l'ho gia spiegato in un altro post(si puo chiudere).
    In questo caso fare si che il tipo sia un vector di tipo generico simile ad un variant mi farebbe comodo , avrei una funzione virtuale con un parametro variant anzichè una funzione template di cui non posso utilizzare il polimorfismo(che vorrei assolutamente usare).

    è possibile o è una sciocchezza?

    grazie.


    ps. non posso usare boost e any.

  5. #5
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Se per tipo generico intendi qualcosa tipo boost::any, no.
    Se per tipo generico intendi una classe ottenuta tramite derivazione, puoi usare la classe base.
    Del resto se fosse possibile, non esisterebbe boost::any, giusto?

    (Tralascio il void* perché si perdono tutte le informazioni su come risalire al tipo corretto).
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  6. #6
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826
    ripensandoci risolverei cosi:
    codice:
    class Writer {
    public:
    	
    	template < class T>
    	void Save(T& vect)
    	{
    	
    	}
    	
    	template < class T, class Allocator , class U >
    	void Save(T& vect)
    	{
    		int count = vect.size();
    		T::iterator itBegin = vect.begin(),
    			itEnd = vect.end();
    		for(; itBegin != itEnd; ++itBegin)
    		{
    			Save<U>(*itBegin);//qui chiama le altre funzioni template con la specializzazione
    		}
    	}
    	
    	template<>
    	void Save<float>(float& f)
    	{
    		std::cout << "write" << f << "  "; 
    	}
    
    	template<>
    	void Save<std::string>(std::string& str)
    	{
    		std::cout << "write" << str.c_str() << "  "; 
    	}
    
    };
    
    class Sizer {
    public:
    	Sizer(){m_size_of_buffer = 0;}
    	template < class T>
    	void Save(T& vect)
    	{
    	
    	}
    	
    	template < class T, class Allocator , class U >
    	void Save(T& vect)
    	{
    		int count = vect.size();
    		T::iterator itBegin = vect.begin(),
    			itEnd = vect.end();
    		for(; itBegin != itEnd; ++itBegin)
    		{
    			Save<U>(*itBegin);
    		}
    	}
    	
    	template<>
    	void Save<float>(float& f)
    	{
    		m_size_of_buffer += sizeof(f);
    		std::cout << sizeof(f) << "  "; //qui andrebbe a incrementare il contatore del buffer da creare
    	}
    
    	template<>
    	void Save<std::string>(std::string& str)
    	{
    		std::cout << "write" << str.c_str() << "  "; 
    	}
    	int m_size_of_buffer;
    };
    
    
    int main(int argc, char* argv[])
    {
    	
    
    	std::vector<float> v;
    	v.push_back(1.3f);
    	v.push_back(1.4f);
    	
    	Sizer w;// o Writer w
    	
    	w.Save<std::vector<float>, std::allocator<float>, float >(v);
    	
    	float f = 1.2f;
    	w.Save<float>(f);
    
    	std::cout << w.m_size_of_buffer;
      
    	return 0;
    }
    il problema è che fino ad adesso usavo due classi e una classe base .
    ho una serie di classi entità che hanno al loro interno una funzione
    codice:
    void save(CBase* pBase)
    {
    pBase->save<float>(m_width);//per esempio
    }
    e ho tutti gli indirizzi in una mappa di functional delle funzioni save dei vari oggetti.
    in un ciclo passo la classe Sizer e in un altro quella writer , come faccio a passare in successione le due classi ? devo usare ancora i template ! ma con le policy classes per es ? come?
    il fulcro attorno a cui non ho ancora capito è proprio questo coi template, sono legato mentalmente al meccanismo virtual runtime.
    quel CBase* pBase permette il passaggio delle classi derivate da CBase, ma con i template come posso fare?
    mi puo aiutare quanto mi hai detto nel post precedente?
    non riesco ancora a capire.

    scusa se ti rompo ma vorrei capire.

    intanto grazie 1000

  7. #7
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Da quel che vedo qui i template c'entrano pochetto.
    Osserva le due classi: praticamente (a meno di un dato in Sizer) hanno gli stessi metodi.
    Metodi tra l'altro che vanno comodamente in overload senza dover scomodare la specializzazione dei template.
    In pratica non c'è differenza tra scrivere:
    codice:
    	template<>
    	void Save<float>(float& f )
    	{
    		std::cout << "write" << f << "  "; 
    	}
    e
    codice:
    	void Save(float& f)
    	{
    		std::cout << "write" << f << "  "; 
    	}
    dato che una funzione specifica è la prima scelta del compilatore.
    (Non ho capito il perché di float& , devi modificarlo?)

    Poi quella:
    codice:
    	template < class T, class Allocator , class U >
    	void Save(T& vect) etc...
    mi pare una forzatura.
    Primo: non hai garanzie che T sia un vector (vero che puoi forzare la specializzazione, ma è un pena farlo ogni volta);
    secondo: Allocator non lo usi in quella funzione e non c'è un parametro a cui faccia riferimento;
    terzo: quel parametro U ti serve solo a richiamare la funzione Save<U> forzando la specializzazione(il che come detto sopra non serve se le varie Save sono in overload).

    Dando per scontato che i metodi di Writer e Sizer facciano cose diverse ed è necessario usare un container (che non sia per forza un vector) e basandosi sul codice che hai mostrato, io farei così:
    codice:
    class CBase {
        public:
            virtual ~CBase() {}
            virtual void Save(float& )=0; 
            virtual void Save(std::string& )=0; 
            // eventuali altri overload = 0;
    
            // intercetta tutte le chiamate a Save non specializzate 
            // dagli overload precedenti.
            template <typename T>
            void save(T& ) {}  
    
            // elabora i dati provenienti da un container
            template <typename Iterator>
            void Save(Iterator a, Iterator z) {
                while (a != z) {
                    this->Save(*a);
                    ++a; 
                }
            } 
    };
    
    
    class Writer : public Cbase {
        public:
        // costruttori, distruttori etc.
    
            virtual void Save(float& ) { /* fa qualcosa */ } 
            virtual void Save(std::string& ) { /* fa qualcosa */ } 
            // eventuali altri overload { /* fanno qualcosa */ }
    };
    
    class Sizer : public Cbase {
        public:
        // costruttori, distruttori etc.
    
            virtual void Save(float& ) { /* fa qualcosa */ } 
            virtual void Save(std::string& ) { /* fa qualcosa */ } 
            // eventuali altri overload { /* fanno qualcosa */ }
    };
    
    int main (etc) {
    
    	std::vector<float> v;
    	v.push_back(1.3f);
    	v.push_back(1.4f);
    	
    	Sizer w;// o Writer w
    	
    	w.Save(v.begin(), b.end()); 
    	float f = 1.2f;
    	w.Save(f);
    
    	std::cout << w.m_size_of_buffer;
    
            // esempio 2 con un container 
            CBase* cb[2];
            cb[0] = new Sizer;
            cb[1] = new Writer;
    
            cb[0]->Save(v.begin(), b.end());
            cb[1]->Save(v.begin(), b.end());
    
            cb[0]->Save(f);
            cb[1]->Save(f);
    
            delete cb[0];  
            delete cb[1];  
    
    	return 0;
    }
    Ora (e mi riallaccio anche a un tuo post passato), la classe CBase non è un'interfaccia pura come intesa in Java, però i dati della funzione Save non fanno nessun riferimento a dati membro di CBase, ma solo a dati passati alla funzione. Tutti gli altri metodi sono virtuali puri, pertanto CBase si può considerare una interfaccia pura a tutti gli effetti.
    In pratica la Save di CBase è solo una funzione adapter che richiamerà la funzione specializzata (se presente) delle classi derivate.
    Inoltre lavorando solo con iteratori ti svincoli dall'obbligo di usare solo dei vector, ma puoi usare anche list o deque.
    Nota che così facendo ti sei anche sganciato da Allocator e dal dover specializzare Save forzando il parametro template.
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  8. #8
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826
    grazie semplice , pulito ,giusto ,grazie.
    Devo sempre incasinare piu del necessario.
    ciao .

  9. #9
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826
    soloun altra cosa:
    se le due classi derivate devono fare qualcosa di diverso(sto parlando della funzione con gli iterator) come faccio appunto ad implemntare due funzioni di diverso comportamento template?
    ho letto che le funzioni template non possono essere virtuali, sbaglio?

    In particolare nella classe sizer devo aumentare un contatore membro della classe mentre nella classe writer va bene cosi.

    in pratica
    Save non fanno nessun riferimento a dati membro di CBase, ma solo a dati passati alla funzione. Tutti gli altri metodi sono virtuali puri, pertanto CBase si può considerare una interfaccia pura a tutti gli effetti.
    in pratica le classi derivate di cbase(solo ala csizer in questo caso) devono accedere a variabili membro della loro classe.
    come posso fare?
    inoltre , dato che è un sistema di serializzazione/deserializazione quale è il sistema migliore per voi di ricreare il vector e a riempirlo(dopo averlo salvato) , è possibile inserire dati nel vector utilizzando gli iterator o devo per forza passare il vector come argomento?

  10. #10
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826
    ho visto che ci sono dei back_insert_iterator e dei front_insert_iterator

    http://www.cplusplus.com/reference/i...sert_iterator/

    ,io cerco di staccarmi dal tipo di container (e questo mi sembra che lo facciano) ma come tipo alla funzione template, è giusto passare qualcosa come:
    std::back_insert_iterator< std::vector<int> >?

    non capisco che tipo passare alla funzione template che mi riempierà l'iterator, questo per rendere generico l'inserimento a tutto il progetto e a tutti i tipi di container.
    è il massimo che si puo fare o conoscete qualcosa di meglio?

    grazie.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.