Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Reflection: newInstance
Forum - C/C++ - Reflection: newInstance

Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 14:29
Giovedì, 09/06/2016
Buongiorno a tutti,
sto cercando (invano) di creare un sistema di reflection per il c++ che genera diverse informazioni a compile-time per le nuove classi dichiarate dal programmatore.

Ora.... Io voglio poter fare una cosa del genere...
sapendo che ogni classe su cui la reflection funziona eredita da ReflectableObject io voglio creare una funzione template che dato un tipo ne restitusce una istanza:
Codice sorgente - presumibilmente C++

  1. template <class T>
  2. SeaDragon::ReflectableObject* createReflectableObject();
  3.  
  4. template <class T> SeaDragon::ReflectableObject* createReflectableObject() {
  5.         return new SeaDragon::ReflectableObject();
  6. }


L'errore del compilatore (MSVC) è: "dichiarazione/definizione di modello non riconoscibile".

Come potete notare non uso nemmeno il tipo passato come argomento di template: al compilatore da fastidio che il tipo di ritorno sia SeaDragon::ReflectableObject*.

Se uso void* tutto "funziona":
Codice sorgente - presumibilmente C/C++

  1. template <class T>
  2. void* createReflectableObject();
  3.  
  4. template <class T> void* createReflectableObject() {
  5.         return (void*)(new SeaDragon::ReflectableObject());
  6. }



La domanda è questa: Cosa ha di sbagliato il codice sopra? Perchè al compilatore crea così tanti problemi?
Dove sto sbagliando?

Questo codice è perfettamente valido:
Codice sorgente - presumibilmente C/C++

  1. template <class T>
  2. void* createReflectableObject();
  3.  
  4. template <class T> void* createReflectableObject() {
  5.         return (void*)(new T());
  6. }


ma io voglio questo:
Codice sorgente - presumibilmente C/C++

  1. template <class T>
  2. SeaDragon::ReflectableObject* createReflectableObject();
  3.  
  4. template <class T> SeaDragon::ReflectableObject* createReflectableObject() {
  5.         return (SeaDragon::ReflectableObject*)(new T());
  6. }



perchè poi voglio fare:
Type::getType("nome del mio tipo")->newInstanceWithoutArgs();

e newInstanceWithoutArgs() richiama il membro di classe Type:
Codice sorgente - presumibilmente Plain Text

  1. SeaDragon::ReflectableObject* (*puntatoreAFunzioneCheCreaLaNuovaIstanza)();



in questo modo:
Codice sorgente - presumibilmente Plain Text

  1. this->puntatoreAFunzioneCheCreaLaNuovaIstanza();



Ma tutto questo non sta in piedi se il compilatore non accetta di compilare una funzione template che ritorna ReflectableObject.

PM Quote
Avatar
HeDo (Founder Member)
Guru^2


Messaggi: 2765
Iscritto: 21/09/2007

Segnala al moderatore
Postato alle 14:36
Giovedì, 09/06/2016
Ti consiglio la lettura di questo topic su StackOverflow

http://stackoverflow.com/questions/41453/how-can-i-add-ref ...

PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 15:28
Giovedì, 09/06/2016
Ho già letto quel topic diverse volte, la prima volta ne è anche nata una discussione su pierotofy.it (il topic dovrebbe avere qualche mese).

Al momento ho risolto senza problemi usando la funzione:
Codice sorgente - presumibilmente C/C++

  1. template <class T>
  2. void* createReflectableObject();
  3.  
  4. template <class T> void* createReflectableObject() {
  5.         return (void*)(new T());
  6. }



e facendo uno static_cast da void* a ReflectableObject*, ma non capisco perchè il compilatore si rifiuti di compilare
Codice sorgente - presumibilmente C/C++

  1. template <class T>
  2. ReflectableObject* createReflectableObject();
  3.  
  4. template <class T> ReflectableObject* createReflectableObject() {
  5.         return (ReflectableObject*)(new T());
  6. }



visto che poi non ha alcun problema a fare:

Codice sorgente - presumibilmente Plain Text

  1. static_cast<ReflectableObject*>(this->constructWithoutArgs());



Non mi sembra un comportamento desiderabile.

PM Quote
Avatar
lumo (Member)
Expert


Messaggi: 449
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 19:55
Venerdì, 10/06/2016
Ci dev'essere qualche errore bastardo, potresti mettere una parte della dichiarazione di ReflectableObject? Non mi è ben chiaro cosa vuoi ottenere

PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 20:23
Venerdì, 10/06/2016
La classe ReflectableObject è vuota: non c'è niente.
Al momento della scrittura di quel codice era semplicemente fatta così:
Codice sorgente - presumibilmente C++

  1. namespace SeaDragon {
  2.         namespace Reflection {
  3.                 class Type;
  4.  
  5.                 class SEADRAGON_API ReflectableObject {
  6.                    
  7.                 };
  8.         }
  9. }



Questa classe servirà per implementare proprietà utili alla reflection, ma al momento è completamente inutilizzata.

Comunque su GitHub: https://github.com/NeroReflex/SeaDragon

Puoi vedere cosa voglio ottenere esattamente: https://github.com/NeroReflex/SeaDragon/blob/master/test/reflection.cpp

Se guardi l'ultimo test vedi che alla fine tutto è fatto per ottenere una istanza di Type da una stringa contenente il nome con cui è stato registrato il tipo.

Codice sorgente - presumibilmente Plain Text

  1. SeaDragon::Reflection::ReflectionSystem::GetType(QUOTE(reflection_support));


si risolve in
Codice sorgente - presumibilmente Plain Text

  1. SeaDragon::Reflection::ReflectionSystem::GetType("reflection_support");


e ciò è valido: il tipo è stato rgistrato poche righe sopra:
Codice sorgente - presumibilmente Plain Text

  1. REGISTER_REFLECTABLE_TYPE(reflection_support);



reflection_support eredita da ReflectableObject, solo che al momento della scrittura della domanda ReflectableObject era vuota.
Ora c'è una funzione pubblica e un membro privato. La funzione ritorna il valore del membro privato.

Nient'altro. Non c'è modo di modificare il membro privato (che è li solo come antefatto di un esperimento).

In ogni caso.... vuota o non vuota la build fallisce, quindi attualmente registro una funzione che dato un tipo ne crea una nuova istanza e  ritorna l'indirizzo iniziale come void*, la funzione newInstanceWithoutArgs() richiama quella funzione, fa un cast (nemmeno tanto semplice, visto che è un static_cast<ReflectableObject*>( ... ), e non un (ReflectableObject*)( ... )):

Codice sorgente - presumibilmente C/C++

  1. ReflectableObject* Type::newInstanceWithoutArgs() {
  2.         return static_cast<ReflectableObject*>(this->newInstanceFunction());
  3. }



Mi scoccia un po' dover fare il cast su newInstanceWithoutArgs, non è affatto elegante, ma a quanto pare il compilatore non mi permette i fare il altro modo.

PM Quote