2011-03-28 15 views
6

Ho una classe A:implicita conversione a un oggetto C++ template

template <typename T, int I> struct A {}; 

e una classe B. Vorrei oggetto di di tipo B per convertire in modo implicito alla A quando somministrato come argomenti della funzione. B si presenta così:

template <typename T> 
struct B { 
    operator A<T,0> &() const { return *new A<T,0>(); } 
}; 

Tuttavia, la mia prova (sotto) non riesce con GCC 4.5, dando l'errore: funzione di nessuna corrispondenza per la chiamata al 'test (B &)' Dove sto andando male qui? Anche altri compilatori lo rifiutano?

template <typename T, int I> 
void test(A<T,I> &a) { delete &a; } 

int main(int argc, char *argv[]) 
{ 
    B<int> b; 
    test(b); 
    return 0; 
} 

p.s. Ora ho inserito la mia soluzione in una risposta qui sotto.

+0

rilevo la perdita di memoria, ma sembra come se questo è stato appena messo insieme per mostrare il problema, quindi non lo farò. Invece inviterò. :-) – James

+0

classe? -------- –

+0

Grazie James :) Risolto. – user2023370

risposta

2

Se si vuole una conversione implicita da B ad A si avrebbe bisogno di uno:

Un operatore cast B:

operator A<T,0>(); 

o un Un costruttore che prende un riferimento B:

A(const B& other); 

o per B derivare da A. Quello che avete dichiarato:

operator A<T,0> &() const; 

sembra un indirizzo errato di sovraccarico.

Tuttavia, dal momento che test() prende un riferimento (e non costante a quello), l'opzione dell'operatore di trasmissione non funzionerà.

Questo è quello che ho provato:

template <typename T, int I> struct A {}; 

template <typename T> 
struct B { 
    //operator A<T,0> &() const { return *new A<T,0>(); } 

    template< int I > 
    operator A<T, I>() const { return A< T, 0 >(); } 
}; 

template <typename T, int I> 
void test(A<T,I> &) { } 

int f() 
{ 
    B<int> b; 

    A<int, 0> a(b); 
    test(a); // <-- Success 

    test(b); // <-- Failure, "could not deduce template argument" 
    return 0; 
} 

conversione ad una inizializzando una variabile locale funziona bene.

+0

Per parafrasare in un modo a mano: Poiché test() prende un riferimento non const a un A, è necessario passare qualcosa con tipo A che può cambiare. Dal momento che B non deriva da A, nulla di ciò che puoi dichiarare in B ti consente di farlo in modo implicito. – RobH

+0

Non l'ho mai fatto, ma penso che sia possibile dichiarare un operatore di conversione che restituisce 'A <...> &' se viene usato typedef. Naturalmente, perché ciò sia utile, B deve avere un'istanza non const di A in esso. – Arkadiy

3

Non correlato al problema, ma return *new A<T,0>(); è errato in quanto perde memoria invita una perdita di memoria. È necessario non utilizzare new qui. return A<T, 0>(); e la rimozione del riferimento dal tipo restituito funziona correttamente e non perde memoria.

+0

Grazie Konrad. Credo che mi costringerebbe a fare test accettare solo argomenti di riferimento const? – user2023370

+0

'test' prende il suo parametro con riferimento non-const, che è ancora più confuso (se vuole modificare il suo parametro). –

+0

@ user643722 Vero. Potresti sovraccaricarlo però. –

1

Sei sicuro di volere una conversione così implicita qui? Sembra un modo perfetto per confondere se stessi o un altro manutentore, o peggio, chiamare una funzione usando l'argomento sbagliato perché la conversione implicita lo consente. Invece, considera un modello make_A come std::make_pair per mostrare esplicitamente la tua intenzione sul sito di chiamata.

+0

Grazie Marco. Il codice viene generato automaticamente e, una volta trovata una soluzione, non verrà modificata dagli utenti finali. – user2023370

+0

@ user643722 Quindi questo è ancora più di un motivo per utilizzare la chiamata esplicita poiché viene generata automaticamente. Presumibilmente gli umani devono ancora leggere il codice. –

0

Questo errore si verifica anche in VC++. Per farlo funzionare, aggiungere questo metodo:

template <typename T> 
void test(B<T> &b) 
{ 
    test(static_cast< A<T,0>& > (b)); 
} 

questo richiederà un vero e proprio B, fare in modo esplicito la conversione (via static_cast), e quindi chiamare test utilizzando il A abbiamo appena fatto.

Ottengo errori quando lo eseguo comunque. Spero che questo sia solo un codice di esempio, e non stai facendo delete &a nel tuo codice attuale. RobH ha fornito un operatore di conversione migliore per te ed evita il fastidio del puntatore.

+0

Probabilmente dovresti lanciarlo su un riferimento: 'static_cast &> (b)', altrimenti viene eseguita una copia che prova tenta di eliminare. – UncleBens

+0

D'oh! Sì, questo risolve il mio problema. Buona cattura, @UncleBens – Tim

1

Fornire un sovraccarico di test come il seguente consentirà di scrivere test(b) come nella domanda.
Per esempio:

template <typename T> 
void test(B<T> const &b) { 
    test(static_cast< A<T,0>& >(b)); 
} 

test(b); // caller 

Se tale sovraccarico non è consentito, ma v'è permesso di modificare s' B definizione, come circa fornire funzione di membro che restituisce A come il seguente, invece di funzione di conversione?

template <typename T> 
struct B { 
    A<T,0> &to_A() const { return *new A<T,0>(); } 
}; 

test(b.to_A()); 

Se non ti è permesso di modificare la definizione B s', quanto sopra to_A sarà una funzione libera come la seguente, invece di funzione membro:

template <typename T> 
A<T,0> &to_A(B<T> const &b) { 
    return static_cast< A<T,0>& >(b); 
} 

test(to_A(b)); 

Spero che questo aiuti

0

Ho optato per l'utilizzo dell'operatore di conversione del passaggio per valore suggerito da Konrad; la chiamata della funzione template esplicita di Let_Me_Be; e ho aggiunto un po 'di magia C++ 0x in cima: un riferimento di rvalue sul parametro da testare. (O, che dovrebbe essere C++ 2011 ora?)

template <typename T, int I> struct A { int x; }; 

template <typename T> 
struct B { 
    operator A<T,0>() const { return A<T,0>(); } 
}; 

template <typename T, int I> 
void test(A<T,I> &&a) { a.x=7; printf("%d\n", x); } 

int main(int argc, char *argv[]) 
{ 
    B<int> b; 
    test<int,0>(b); 
    return 0; 
} 
Problemi correlati