2013-06-26 9 views
7

Devo sovraccaricare gli operatori aritmetici di base per alcuni oggetti molto complicati che ho creato. Finora, ho implementato con successo operator*; ora ho bisogno di operator+, ecc. Il codice per operator* è molto grande, ma l'unica differenza tra operator* e operator+ sarà una riga dove uso + invece di * su alcuni numeri complessi. Questa linea sarà all'interno di un ciclo che viene chiamato molte volte, quindi voglio che sia efficiente, il che sembra non implicare alcun riferimento a funzioni. (Correggimi se ho torto.)Operatore di passaggio come parametro modello di funzione

Questo sembra un uso perfetto per i modelli. Ma sono in perdita per la sintassi corretta. Sto pensando qualcosa di simile all'interno della definizione di ComplicatedObject classe:

template <typename ComplexBinaryOp> 
ComplicatedObject BinaryOp(const ComplicatedObject& B) const { 
    // Do lots of stuff 
    for(unsigned int i=0; i<OneBazillion; ++i) { 
    // Here, the f[i] are std::complex<double>'s: 
    C.f[i] = ComplexBinaryOp(f[i], B.f[i]); 
    } 
    // Do some more stuff 
    return C; 
} 

inline ComplicatedObject operator*(const ComplicatedObject& B) const { 
    return BinaryOp<std::complex::operator*>(B); 
} 

inline ComplicatedObject operator+(const ComplicatedObject& B) const { 
    return BinaryOp<std::complex::operator+>(B); 
} 

Questa domanda è legata: "function passed as template argument". Ma le funzioni passate come gli argomenti del template non sono operatori.

Ho simulato la sintassi in ogni modo possibile, ma il compilatore si lamenta sempre di una sintassi errata. Come dovrei farlo?

Edit:

Per chiarezza, includo la soluzione completa in termini di mio codice di cui sopra, insieme con le generalizzazioni ulteriori persone possono avere bisogno:

template <typename ComplexBinaryOp> 
ComplicatedObject BinaryOp(const ComplicatedObject& B) const { 
    // Do lots of stuff 
    for(unsigned int i=0; i<OneBazillion; ++i) { 
    // Here, the f[i] are std::complex<double>'s: 
    C.f[i] = ComplexBinaryOp()(f[i], B.f[i]); // Note extra()'s 
    } 
    // Do some more stuff 
    return C; 
} 

inline ComplicatedObject operator+(const ComplicatedObject& B) const { 
    return BinaryOp<std::plus<std::complex<double> > >(B); 
} 

inline ComplicatedObject operator-(const ComplicatedObject& B) const { 
    return BinaryOp<std::minus<std::complex<double> > >(B); 
} 

inline ComplicatedObject operator*(const ComplicatedObject& B) const { 
    return BinaryOp<std::multiplies<std::complex<double> > >(B); 
} 

inline ComplicatedObject operator/(const ComplicatedObject& B) const { 
    return BinaryOp<std::divides<std::complex<double> > >(B); 
} 
+1

'std :: complex' è un modello di classe, quindi è necessario' std :: complex '. Ma anche allora, 'complesso :: operator *' e 'complesso :: operator +' sono * funzioni membro *. Non puoi semplicemente passarli in giro senza un'istanza di 'complesso ' su cui operare. – Praetorian

+0

Post errori che stai ricevendo. –

+1

+1 per una domanda interessante. Ho anche trovato questa domanda - [puntatori C++ agli operatori] (http://stackoverflow.com/questions/4176895/c-pointers-to-operators) pertinenti e interessanti. – keelar

risposta

4

Penso std::plus<std::complex> e std::multiplies<std::complex> sono ciò che si' sto cercando, ma non sono sicuro al 100% di aver capito la tua domanda (è il tuo frammento di codice all'interno di una classe che non ci stai mostrando?)

+0

+1, penso che questo sia quello che l'OP sta cercando anche, ma dovrebbe essere 'più >' e 'moltiplica >' – Praetorian

+0

@Praetorian: così 'plus' e' moltiplica' possono essere usati senza specificare lo scope 'std'? – keelar

+0

+1 Sì, questo sembra quello che voglio, va bene (anche se @Praetorian ha ragione). Ma non riesco a capire come usare queste funzioni. Il compilatore obietta sulla mia riga 'ComplexBinaryOp (f [i], B.f [i])'. Qualche aiuto su questo? – Mike

1

Hai due opzioni. Passare la funzione in fase di esecuzione:

#include <functional> 

template <typename ComplexBinaryOp> 
ComplicatedObject BinaryOp(const ComplicatedObject& B, ComplexBinaryOp op) const { 
    // ... 
    C.f[i] = op(f[i], B.f[i]); 
    // ... 
} 

// functor wrapping member function pointer 
BinaryOp(B, std::mem_fn(&std::complex<double>::operator+)); 

// standard-issue functor 
BinaryOp(B, std::plus<std::complex<double>>()); 

O passare a tempo di compilazione:

// or another floating-point type 
typedef double (*ComplexBinaryOp)(double, double); 

template <ComplexBinaryOp op> 
ComplicatedObject BinaryOp(const ComplicatedObject& B) const { 
    // ... 
    C.f[i] = op(f[i], B.f[i]); 
    // ... 
} 

// non-member function 
template<class T> 
std::complex<T> add_complex(const std::complex<T>& a, const std::complex<T>& b) { 
    return a + b; 
} 

// non-member function pointer 
BinaryOp<add_complex<double>>(B); 

io credo che si possa fare lo stesso con puntatori alle funzioni membro come pure cambiando la definizione di ComplexBinaryOp.

+0

Questi sembrano possibilità utili. Proverò le cose e tornerò da te. Grazie! – Mike

+0

La mia sintassi originale funziona perfettamente, dopo aver sostituito 'std :: complex :: operator *' con 'std :: moltiplica', ecc. Anche i tuoi lavori funzionano, ma mi sembrano meno semplici. – Mike

+1

@ Mike: Sì, funziona anche tu. Bisogna dire 'ComplexBinaryOp() (foo, bar)' per ottenere effettivamente l'istanza del functor, però. Ciò può essere fatto anche all'interno o all'esterno come nel mio primo esempio. –