2012-11-28 16 views
5

voglio essere in grado di passare i riferimenti degli oggetti ereditati da DBMetaData come argomento di modello non standardizzate di un'altra classe, DBVar:C argomento di un template non standardizzate ++ prendendo ereditato classe

#include <iostream> 

class DBMetaData 
{ 
public: 
    virtual const char *description() const = 0; 
}; 

class DBMetaData_NT 
: public DBMetaData 
{ 
public: 
    const char *description() const 
    { return "Useless description."; } 
}; 

#if DO_WHAT_I_WANT 
template< const DBMetaData &Metadata > 
#else 
template< typename MetadataType, 
    const MetadataType &Metadata > 
#endif // DO_WHAT_I_WANT 
class DBVar 
{ 
public: 
    /// Descrição da variavel. 
    const char *description() const 
    { return Metadata.description(); } 
}; 

DBMetaData_NT  _md_u1; 

#if DO_WHAT_I_WANT 
DBVar<_md_u1> _u1; 
#else 
DBVar< DBMetaData_NT, _md_u1 > _u1; 
#endif // DO_WHAT_I_WANT 

int main() 
{ 
    std::cout << "_md_u1.description() = " << _md_u1.description() << std::endl; 
    std::cout << "_u1.description() = " << _u1.description() << std::endl; 

    return 0; 
} 

posso compilare ed eseguire l'esempio precedente ma Ho bisogno di specificare esplicitamente il tipo ereditato.

Se provo a compilarlo definire DO_WHAT_I_WANT (voglio passare un riferimento - o un puntatore - di tipo DBMetaData ad un oggetto di qualsiasi classe ereditata), ottengo l'errore:

templ_inh_arg.cpp:36:15: error: could not convert template argument ‘_md_u1’ to ‘const DBMetaData&’ 
templ_inh_arg.cpp:36:20: error: invalid type in declaration before ‘;’ token 

Perché puo' t Passaggio _u1, ovvero di tipo DBMetaData_NT che eredita da DBMetaData come parametro per DBVar<_md_u1> _u1;?

C'è un modo per ottenere ciò che voglio?

Grazie!


EDIT:

Sostituzione del parametro di modello con un puntatore a funzione, come suggerito da @ecatmur risolto il mio problema e, devo notare, trasformato il mio codice un po 'più leggibile.

#include <iostream> 

class DBMetaData 
{ 
public: 
    /// Descrição da variavel. 
    virtual const char *description() const = 0; 
}; 

class DBMetaData_NT 
: public DBMetaData 
{ 
public: 
    const char *description() const 
    { return "Useless description."; } 
}; 


typedef  const DBMetaData &(*metadata)(); 

template< metadata Metadata > 
class DBVar 
{ 
public: 
    /// Descrição da variavel. 
    const char *description() const 
    { return Metadata().description(); } 
}; 

const DBMetaData & _md_u1_metadata() 
{ 
    static const DBMetaData_NT  _md_u1; 

    return _md_u1; 
} 

DBVar<_md_u1_metadata> _u1; 

int main() 
{ 
    std::cout << "_md_u1_metadata().description() = " << _md_u1_metadata().description() << std::endl; 
    std::cout << "_u1.description() = " << _u1.description() << std::endl; 

    return 0; 
} 

risposta

4

Sfortunatamente no. Per 14.3.2 modello non-argomenti di tipo, comma 1:

A template-argument for a non-type, non-template template-parameter shall be one of: [...]

  • a constant expression that designates the address of an object with static storage duration [...], expressed (ignoring parentheses) as &id-expression, except that the & [...] shall be omitted if the corresponding template-parameter is a reference.

Derivato-to-base di conversione sono non consentito, al comma 5 della stessa sezione:

  • For a non-type template-parameter of type reference to object, no conversions apply. The type referred to by the reference may be more cv-qualified than the (otherwise identical) type of the template-argument. The template-parameter is bound directly to the template-argument, which shall be an lvalue.

Questo significa anche che un cast non è consentito, poiché non è nella forma [&] id-expression e non produce un lvalue.

A seconda di ciò che si sta tentando di ottenere, è possibile ottenere un risultato simile simulando manualmente il polimorfismo, ad es. avere _md_u1 inizializzato come valore di ritorno di una funzione che imposta un puntatore o una tabella vtable appropriati.

+0

Questo è tutto. Una funzione. Risolve il mio problema. Ho modificato la mia domanda con una soluzione basata sulle funzioni. Grazie! – j4x

+0

Mi chiedo se il termine "covarianza" si applica qui. È noto (http: // StackOverflow.it/questions/2203388/c-templates-polymorphism) che i modelli C++ non sono covarianti. Sembra che si possa affermare che neanche i parametri di tipo non di modello sono covarianti. – pfalcon

1

È possibile farlo con C++ 11 di decltype e una macro come segue:

#define DBVAR(metadata) DBVar<decltype(metadata), metadata> 

Ora, per definire una variabile:

DBVAR(_md_u1) _u1; 

Spero che questo aiuti.

EDIT: Per essere onesti, non mi piace il tuo approccio. Preferirei andare con le funzioni dei membri dei metadati statici o con il polimorfismo basato su modelli diversi.

Problemi correlati