2010-02-19 16 views
5

E 'possibile scrivere una classe:È possibile passare il nome come argomento al modello C++?

template<typename T, ... name> struct Magic { 
    T name; 
}; 

tale che:

Magic<int, foo> gives: 

Magic<int, foo> { 
    int foo; 
} 

e

Magic<float, bar> gives: 

Magic<float, bar> { 
    float bar; 
} 

Fondamentalmente, voglio essere in grado di specificare non solo il tipo, ma anche il nome delle variabili membro.

+0

I modelli gestiscono i tipi. Gli unici nomi a cui possono fare riferimento sono i nomi dei tipi, non i nomi lessicali. Il preprocessore è per i nomi lessicali. – GManNickG

+0

l'unico modo in cui posso pensare è usare l'ereditarietà + pattern crtp, come 'struct bar_variable {float bar; }; struct Magic : named_variable {}; Magia ; ' – Anycorn

risposta

5

Non è possibile, è necessario ricorrere a soluzioni basate su macro o utilizzare un set predefinito di tipi che forniscono membri denominati.

Un possibile approccio macro-based:

#define MAGIC(name_) \ 
    template<typename T> struct Magic1 { \ 
     T name_; \ 
    }; 

MAGIC(foo); 

o:

#define MAGIC(type_, name_) \ 
    struct Magic1 { \ 
     type_ name_; \ 
    }; 

MAGIC(foo); 

Usando la magia preprocessore, per esempio utilizzando Boost.Preprocessor, dovresti essere in grado di generare n membri con nome in un modo più conveniente.

Un altro approccio potrebbe essere utilizzando un insieme predefinito di classi che forniscono alcuni membri nominati in che si eredita:

enum { MemberNameFoo, MemberNameBar }; 

template<class T, int id> 
struct named_member; 

template<class T> 
struct named_member<T, MemberNameFoo> { 
    T foo; 
}; 

template<class T> 
struct named_member<T, MemberNameBar> { 
    T bar; 
}; 

// holder for the above, just one member for this example: 

template<class T, int name> 
struct holder : named_member<T, name> {}; 

// using it: 

typedef holder<int, MemberNameFoo> HasFoo; 
typedef holder<int, MemberNameBar> HasBar; 

Utilizzando compilare in tempo le liste si potrebbe poi ereditare da nnamed_member istanze, Boost.MPL potrebbe aiutare qui .

+0

Se in realtà non ti interessa troppo quello che i tuoi membri sono nominati esattamente, puoi farlo con le liste di caratteri o con i modelli variadici C++ 0x. L'ho fatto per implementare le classi che hanno scritto i propri metodi di serializzazione e deserializzazione. – Omnifarious

+0

Ma la domanda riguarda il suo * "possibile passare il nome [s]" * a un modello, non come generare un titolare per una raccolta di tipi chiamata arbitrariamente. –

+0

@ gf, questo è vero. Anche se spesso le persone non pongono la domanda che intendono esattamente. Hanno in mente una soluzione per un problema e chiedono come far funzionare la soluzione, non come risolvere il problema reale.:-) – Omnifarious

1

No, non è possibile. C'è un costrutto chiamato typelist che può essere usato per ottenere un effetto come quello che stai cercando. Sfortunatamente, anche se non riceverai membri nominati, otterrai funzioni di accesso con nomi come MyClass::getField<1>().

In C++ 0x si può fare meglio delle liste di caratteri con variadic templates. Ma avrai ancora funzioni di accesso che assomigliano al caso C++.

È allettante mettere giù un esempio di modello variadico qui perché non sarebbe troppo grande. Sfortunatamente penso che farlo bene richiederà alcune ore di ricerca da parte mia per imparare esattamente come funzionano i modelli variadici. Potrei fare una versione stupida relativamente facilmente, ma mi aspetto che la versione stupida sarebbe molto meno bella in vari modi di una versione ben fatta.

Problemi correlati