2014-09-22 9 views
6

Nel mio codice ho una classe che registra il metodo di altre classi:Sostituzione di vuoto come parametro per il metodo basato su modelli

#include <iostream> 
using namespace std; 

template< typename C> 
    class Reg { 
    public: 
    template< typename R, typename A> 
     void register_f(string name, R (C:: *method_p) (A)) { /*registration process*/ } 

// template< typename R> 
//  void register_void_f(string name, R (C:: *method_p) (void)) { /*registration process*/ } 
    }; 

    class A { 
    public: 
     int f(void) { return 1; } 
     void g(int x) { /* some code*/ } 
    }; 


    int main() { 
     Reg< A> r; 

     r.register_f("g", &A::g); 
/*1*/// r.register_f("f", &A::f); 
/*2*/// r.register_f< int, void>("f", &A::f); 
/*3*/// r.register_void_f< int>("f", &A::f); 

     return 0; 
    } 

http://ideone.com/X8PNLC

linea decommentando/* 2 */mi dà un errore:

template argument deduction/substitution failed:

In substitution of ‘template void register_f(std::string, R (C::*)(A)) [with R = R; A = A; C = A] [with R = int; A = void]’:

error: invalid parameter type ‘void’

Line/* 1 /è lo stesso/ 2 * /, ma con il messaggio di errore non così informativo.

Capisco che per risolvere il problema è possibile utilizzare il metodo register_void_f, ma non voglio farlo perché register_f è una parte della mia API finale.

Domanda> come risolvere gli errori di compilazione senza introdurre register_void_f?

Ho un'idea per risolverlo con parziale specializzato register_f, ma non so come farlo in quanto in C++ non è possibile specializzare parzialmente il metodo basato su modelli.

PS> Non riesco a utilizzare C++ 11.

risposta

2

sovraccarico vostra funzione:

void foo(int) {} 
double bar() { return 3.14; } 

template< class R, class A > 
void test( R (*method_p) (A)) { } 
template< class R > 
void test( R (*method_p)()) { } 

int main(){ 
    test(foo); 
    test(bar); 
} 

live example

conversione di questo al fatto che è i metodi dovrebbero essere facili

+0

Grazie Yakk, stranamente funziona! http://ideone.com/Jk3NOp –

+0

Ho pensato che sarebbe stato difficile specializzarlo. –

+0

@ValentinT. l'override non è la specializzazione. La specializzazione è diversa e * di solito * una cattiva idea con le funzioni (è meglio ignorare). Se hai bisogno di una specializzazione sofisticata, di solito vai in una classe in cui hai pieno di macchinari per la specializzazione, e non la specializzazione del modello di funzione menomata e confusa. – Yakk

3

Non utilizzare void per argomenti, utilizzare nulla - qualcosa di simile:

template< typename R> 
    void register_void_f(string name, R (C:: *method_p)()) { /*registration process*/ } 
+0

Il problema è come farlo senza ** ** register_void_f. Penso che usare o no ** void ** non faccia differenza. –

+0

che ne dici di sovraccaricare 'register_f' con una versione senza parametro? – Alex

+0

usando l'ereditarietà, vuoi dire? –

2

è possibile utilizzare il seguente:

template< typename C> class Reg; 

template <typename C, typename F> struct helper; 

template <typename C, typename R, typename A> 
struct helper<C, R (C::*)(A)> 
{ 
    void operator() (Reg<C>& reg, const std::string& name, R (C::*method)(A)) const { /* Your implementation */} 
}; 

template <typename C, typename R> 
struct helper<C, R (C::*)()> 
{ 
    void operator() (Reg<C>& reg, const std::string& name, R (C::*method)()) const { /* Your implementation */} 
}; 


template< typename C> 
    class Reg { 
    public: 
    template< typename F> 
     void register_f(const std::string& name, F method) { helper<C, F>()(*this, name, method); /*registration process*/ } 

    }; 

e usarlo in questo modo:

Reg< A> r; 

r.register_f("g", &A::g); 
r.register_f("f", &A::f); 
r.register_f<int (A::*)(void)>("f", &A::f); 
Problemi correlati