2013-07-12 18 views
5

Sto usando xsd per creare codice C++ da un file di schema xml. Per un tipo xml vengono create più funzioni (per la serializzazione, ecc.).
Se il tipo è chiamato XmlType sono creati molteplici funzioni della forma seguente:più funzioni con lo stesso nome ma diversi tipi di argomenti come parametro di modello

XmlType XmlType_(const XmlType& a, const string& b) 
string XmlType_(const XmlType& a) 
... 

Questo sono le normali funzioni e non membri del XmlType e tutti hanno lo stesso nome. Per XmlType2 le funzioni si chiamerebbero XmlType2_.

Vorrei scrivere una classe modello di utilità per tutti i diversi tipi xml del mio schema xml. Le diverse funzioni verranno chiamate intuizione in questa classe. Quello che ho finora è qualcosa di simile:

template<typename T> 
using TFunc1 = T (*)(const T&, const string&); 
template<typename T> 
using TFunc2 = string (*)(const T&); 

template<typename T, TFunc1<T> func2, TFunc2<T> func2> 
class XmlUtil { 
... 
}; 

Quando creare un'istanza della XmlUtil classe se hanno a che fare in questo modo:

XmlUtil<XmlType, XmlType_, XmlType_> util; 

Questo si sente un po 'ridondante e peggiora , quando devo passare più funzioni come parametri.

Vorrei utilizzare la classe util in questo modo:

XmlUtil<XmlType, XmlType_> util; 

o meglio ancora come questo

XmlUtil<XmlType> util; 

L'unico modo che posso pensare è usare in qualche modo definire, ma doesn non mi sembra giusto
C'è un altro modo per farlo?

EDIT: sto usando un definiscono ora:

#define TRPL(name) name, name ## _, name ## _ 
... 
XmlUtil<TRPL(XmlType)> util; 

Io modificare questo, se trovo qualcosa di meglio (forse ignorare set come Yakk suggerito nella sua risposta).

+0

Questo è specifico per C++ 11, credo? –

+0

Sì, sto usando C++ 11 (MinGW con gcc 4.8). Aggiunto il tag. Specializzazione modello – guini

+0

. Fatto un equivalente di Func <> (in C#) in C++ utilizzandolo in cui Execute aveva un'implementazione specifica del parametro template e un conteggio degli argomenti. Utilizzando le impostazioni predefinite nel modello, è possibile scegliere di definire solo alcuni degli argomenti del tipo. –

risposta

3

questo:

XmlUtil<XmlType> util; 

è impossibile perché non c'è modo di ottenere XmlType-XmlType_. La loro relazione viene scartata dopo il generatore di codice automatico.

Tuttavia questo:

XmlUtil<XmlType_> util; 

può essere possibile. È possibile dedurre il tipo di funzione di XmlType_ e quindi utilizzare il tipo di reso dedotto che sarà XmlType. Credo che ci siano funzioni di libreria standard per questo scopo.

Per quanto riguarda i due diversi sovraccarichi, potrebbe essere più complicato. Non penso che sia possibile passare un set di overload di funzioni come parametro template, la risoluzione viene eseguita sull'argomento template nel contesto del parametro template su una funzione. Non penso che ci sia un modo per rinviare questa azione senza usare il preprocessore.

Quindi direi che è necessario utilizzare uno #define. È meglio di niente.

0

Argomenti predefiniti del modello nella definizione della classe?

Come

template<typename T, TFunc1<T> func1 = XmlType_, TFunc2<T> func2 = XmlType_> 
class XmlUtil { 
    // ... 
}; 
+0

Il nome della funzione dipende dal nome del tipo. Quindi penso che questo non funzionerebbe. Ho modificato la domanda per renderla più chiara. – guini

+1

@guini L'ho appena provato e [sembra compilare bene] (http://ideone.com/fu5s8M). Vale la pena provare? –

+0

Se ho capito bene, il nome della funzione XmlType_ è corretto nell'esempio. Ma nel mio caso il nome della funzione cambia. Se ho il tipo Type1, la funzione si chiamerà Type1_, per Type2 si chiamerà Type2_ ecc. – guini

0

È possibile utilizzare una classe di caratteristica come questo

template <typename T> 
struct Trait{ 
    typedef T type; 
    typedef T (*func1)(const T&, const string&); 
    typedef string (*func2)(const T&); 
}; 

e rendere la classe XmlUtil hanno un parametro di modello (chiamiamolo tratto) e utilizzare Trait :: tipo, Trait :: func1 e Trait :: func2. Vedi here per l'utilizzo completo.

Nell'esempio, il tipo di XmlUtil va come:

XmlUtil<Trait<XmlType> > 

ho fatto in questo modo dal momento che non conosco bene il vostro problema.Potrebbe essere il caso che si può solo definire la classe Trait destra in XmlUtil e utilizzare

XmlUtil<XmlType> 

Altre variazioni sono possibili, ma dipende solo da quello che vi serve.

È possibile leggere una breve introduzione alle classi di tratti here. Se vuoi saperne di più su questo argomento ti suggerisco Modern C++ (Alexandrescu).

+0

Grazie per la risposta. Lo guarderò. Ma ho bisogno di un po 'di tempo per capirlo :-) – guini

+0

Ho cambiato il link del codice, ho messo lì alcuni commenti –

+0

Rileggendo la domanda e la risposta Non sono sicuro di aver indirizzato correttamente la tua domanda, dammi un feedback così che posso essere di maggiore aiuto, se necessario. –

0

Non sono sicuro di comprendere appieno cosa stai chiedendo. L'approccio comune per la serializzazione e la deserializzazione sarebbe quello di creare una fabbrica (fabbrica astratta) e risolvere la costruzione degli oggetti in modo dinamico. Si noti che questo può essere migliorato per strutture complesse, in cui il generatore di codice può creare funzioni membro per estrarre il tipo esatto di ciascun membro.

Ma ancora una volta, non capisco pienamente ciò che si sta realmente cercando di fare ... Come raccomandazione credo che sarebbe d'aiuto se hai fornito più di una descrizione del problema da risolvere, come la questione si concentra su come per far funzionare la tua soluzione, e che ignora implicitamente altri approcci che potrebbero essere progetti migliori.

1

Sembra un lavoro per i set di sostituzioni.

static struct foo_override_set_type { 
    template<typename... Args> 
    auto operator()(Args...&& args) const 
    -> 
    decltype(foo(std::forward<Args>(args)...)) 
    { return (foo(std::forward<Args>(args)...)); } 
    template<typename T> 
    operator T() { return foo; } 
} foo_override_set; 

Oggetti di tipo foo_override_set_type rappresentano l'intero set di override di foo. Chiamandoli con operator() esegue una ricerca di set di sostituzioni su foo e chiama la funzione risultante. Lanciarli su un puntatore a una funzione equivale a lanciare il token foo a un puntatore a funzione (o altro valore).

La generazione del codice può generare automaticamente tali tipi di set di sostituzioni. Può anche creare una classe di caratteri che mappa dal tuo tipo XmlType al set di override delle funzioni XmlType_ tramite specializzazione.

Quindi, il tuo XmlUtil<XmlType> può accedere al set di override di XmlType_ tramite tale classe di tratti. In primo luogo crea un'istanza della variabile di impostazione dell'override, quindi invoca ().

Come parte, @Xeo ha una proposta per rendere la creazione di tali oggetti facile come digitare []XmlType_ in C++ 1y o C++ 1z.

+0

Grazie per il tuo suggerimento. Non lo capisco ancora del tutto, ma ci penserò. Hai forse un link ad alcuni documenti sui set di override? – guini

+1

@guini No, non proprio. Un set di override è solo un oggetto che si comporta come se fosse una serie completa di sostituzioni sintattiche di alcuni nomi di funzioni. È possibile farlo con l'inoltro perfetto e un 'modello operatore T' piuttosto bene. Puoi leggere un perfetto forwarding (la tecnica C++ 11 che uso sopra in 'operator()') che può renderlo più sensato. L'operatore 'T' esiste in modo da poter assegnare un set di sovrascrittura a un puntatore a funzione e farlo estrarre la proprietà di override" magicamente ". E poiché è un oggetto senza stato, puoi passarlo o il suo tipo nel punto in cui ti serve. – Yakk

Problemi correlati