2013-06-26 13 views
7

Muszę przeciążyć podstawowe operatory arytmetyczne w przypadku bardzo skomplikowanych obiektów, które utworzyłem. Do tej pory pomyślnie wdrożyłem operator*; teraz potrzebuję operator+ itd. Kod dla operator* jest bardzo duży, ale jedyną różnicą między operator* i operator+ będzie jedna linia, w której używam + zamiast * dla niektórych liczb zespolonych. Linia ta będzie znajdować się wewnątrz pętli, która jest wywoływana wiele razy, więc chcę, aby była wydajna, co wydaje się nie sugerować żadnych wskaźników funkcji. (Popraw mnie, jeśli się mylę.)Przekaż operator jako parametr szablonu funkcji

Wydaje się to być idealnym zastosowaniem do szablonów. Ale brak mi właściwej składni. Myślę, że coś takiego się wewnątrz definicji ComplicatedObject klasy:

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); 
} 

To pytanie jest związane: "function passed as template argument". Ale funkcje przekazane jako argumenty szablonu nie są operatorami.

Miałem do czynienia ze składnią w każdy możliwy sposób, ale kompilator zawsze skarży się na złą składnię. Jak mam to zrobić?

Edit:

Dla jasności, ja to kompletne rozwiązanie w zakresie mojego kodu powyżej, wraz z dodatkowymi uogólnień ludzie mogą potrzebować:

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' to szablon klasy, więc potrzebujesz' std :: complex '. Ale nawet wtedy, 'complex :: operator *' i 'complex :: operator +' są * funkcjami składowymi *. Nie możesz po prostu przekazać ich bez instancji 'complex ' do działania. – Praetorian

+0

Wysyłaj błędy, które otrzymujesz. –

+1

+1 za interesujące pytanie. Też znalazłem to pytanie - [wskaźniki C++ do operatorów] (http://stackoverflow.com/questions/4176895/c-pointers-to-operators) istotne i interesujące. – keelar

Odpowiedz

4

myślę std::plus<std::complex> i std::multiplies<std::complex> co wy” Ponownie szukam, ale nie jestem w 100% pewien, czy rozumiem twoje pytanie (czy jest to fragment kodu w klasie, której nie pokazujesz nam?)

+0

+1, myślę, że tego właśnie szuka OP, ale powinno być 'plus >' i 'mnoży >' – Praetorian

+0

@Praetorian: więc 'plus' i' mnożenie' może być użyte bez określania zakresu 'std'? – keelar

+0

+1 Tak, to wygląda tak, jak chcę, w porządku (chociaż @Praetorian ma rację). Ale nie wiem, jak korzystać z tych funkcji. Kompilator sprzeciwi się mojej linii 'ComplexBinaryOp (f [i], B.f [i])'. Jakaś pomoc w tej sprawie? – Mike

1

Masz dwie opcje. Przekazać w czasie wykonywania funkcji:

#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>>()); 

albo przekazać je w czasie kompilacji:

// 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); 

Wierzę, że można zrobić to samo ze wskaźników funkcji członek, a także poprzez zmianę definicji ComplexBinaryOp.

+0

Te wyglądają jak przydatne możliwości. Wypróbuję rzeczy i wrócę do ciebie. Dzięki! – Mike

+0

Okazuje się, że moja oryginalna składnia działa dobrze, po zamianie 'std :: complex :: operator *' na 'std :: multiplies', itd. Twój również działa, ale wydaje mi się mniej prosty. – Mike

+1

@Mike: Tak, to też działa. Trzeba jednak powiedzieć 'ComplexBinaryOp() (foo, bar)', aby faktycznie uzyskać instancję funktora. Równie dobrze można to zrobić w środku lub na zewnątrz, jak w moim pierwszym przykładzie. –

Powiązane problemy