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