2012-07-31 11 views
14

È noto che gli argomenti del modello possono essere indicatori delle funzioni membro.Detrazione argomento modello per i puntatori funzione membro

così posso scrivere:

struct Bar 
{ 
    int fun(float x); 
}; 

template <int (Bar::*FUN)(float)> 
struct Foo 
{ /*...*/ }; 

typedef Foo<&Bar::fun> FooBar; 

Ma cosa succede se voglio il tipo del Bar in sé ad essere un argomento di un template:

template <typename B, int (B::*FUN)(float)> 
struct Foo 
{ /*...*/ }; 

typedef Foo<Bar, &Bar::fun> FooBar; 

Ora, quando lo uso, devo scrivere Bar due volte!

La mia domanda è: c'è un modo per forzare il compilatore a dedurre automaticamente il tipo di classe?

L'obiettivo è per questo a poco lavoro:

typedef Foo<&Bar::fun> FooBar; 
typedef Foo<&Moo::fun> FooMoo; 

risposta

5

Probabilmente dovresti solo scrivere il nome della classe lì. Tuttavia, se vuoi davvero evitare di usare la magia malvagia dei macro. La versione semplice è più pericoloso:

#define TT(X) decltype(X), X 

template<typename T,T t> 
struct Foo 
{ /* ... */ }; 

struct Bar { 
    int fun(float) {} 
}; 

int main() { 
    Foo<TT(&Bar::fun)> f; 
} 

Ciò accettare qualsiasi tipo di parametro di modello non-tipo, e si possono incontrare difficile da capire gli errori se l'implementazione Foo funziona solo con gli Stati puntatori-a-.

per renderlo un po 'più sicuro è necessario un metafunction che ti dice il nome della classe:

template<typename T> struct member_ptr_traits; 

template<typename Class,typename Ret,typename... Args> 
struct member_ptr_traits<Ret (Class::*)(Args...)> 
{ 
    typedef Class class_type; 
    typedef Ret return_type; 
}; 

#define TT(X) member_ptr_traits<decltype(X)>::class_type , X 

template<typename T,int (T::*FUN)(float)> 
struct Foo 
{ /* ... */ }; 

struct Bar { 
    int fun(float) {} 
}; 

int main() { 
    Foo<TT(&Bar::fun)> f; 
} 

anche entrambi questi usa C++ 11 in modo che non funziona con i vecchi compilatori. Questa semplice versione può essere riscritta per utilizzare il vecchio typeof o estensioni del compilatore simili. Riscrivere la versione più sicura richiede la simulazione di modelli variadici.

+0

In realtà, sto usando dei brutti macros per questo (è un modello interno a una libreria, quindi nessun rischio reale di essere usato in modo improprio). Ad ogni modo, 'member_ptr_traits' è fantastico perché ho davvero bisogno del tipo' T'. – rodrigo

7

Semplice risposta: no, non c'è.

Il problema è che per typedef Foo<&Bar::fun> FooBar; funzionare, il modello dovrebbe avere un singolo argomento non di tipo, ma il tipo di tale argomento sarebbe sconosciuto quando il modello viene dichiarato, che non è valido. D'altro canto, la deduzione di tipo non viene mai applicata agli argomenti del modello (solo agli argomenti per i modelli di funzione, ma questi sono gli argomenti della funzione, non il modello).

+0

Capito. Quindi sarebbe impossibile anche fare una funzione modello, non è vero? – rodrigo

+0

@rodrigo: se vuoi prendere quell'argomento modello come puntatore a membro sì. La domanda è se sia necessario il puntatore al membro per essere un argomento modello, oppure può essere un argomento di funzione, che può essere dedotto. –

+0

Sì, ho bisogno che sia un argomento modello perché deve essere usato per creare un'istanza di un modello annidato. Comunque, grazie per la tua intuizione – rodrigo

Problemi correlati