I have to overload the basic arithmetic operators for some very complicated objects I've made. So far, I've successfully implemented operator*
; now I need operator+
, etc. The code for operator*
is very large, but the only difference between operator*
and operator+
will be one line where I use +
instead of *
on some complex numbers. This line will be inside of a loop that gets called many many times, so I want it to be efficient, which would seem to imply no function pointers. (Correct me if I'm wrong.)
This seems like a perfect use for templates. But I'm at a loss as to the correct syntax. I'm thinking something like this inside the ComplicatedObject
class definition:
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);
}
This question is related: "function passed as template argument". But the functions passed as the template arguments are not operators.
I've fiddled with the syntax every way I can think of, but the compiler always complains of bad syntax. How should I do this?
For clarity, I include the complete solution in terms of my code above, along with the additional generalizations people may need:
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);
}
I think std::plus<std::complex>
and std::multiplies<std::complex>
are what you're looking for, but I'm not 100% sure I understand your question (is your code snippet within a class you aren't showing us?)
You have two options. Pass the function at runtime:
#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>>());
Or pass it at compile-time:
// 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);
I believe you can do the same with member function pointers as well by changing the definition of ComplexBinaryOp
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With