I have been missing some important functionality from std::complex like the ability to add a std::complex<float> and a std::complex<double> or operations like 1+c, i.e. between int and std::complex. My idea was to derive a new class my::complex from std::complex which just inherits everything that is already implemented and adds other stuff.
In order to make the code compatible with functions using std::complex, I added automatic conversion to and from std::complex (and also automatic conversions between my::complex<float> and my::complex<double>).
Now something like
my::complex<float> c1,c2,c3;
c1 = c2 + c3;
works even though I did not implement operator+ myself, since c2 and c3 are cast to std::complex, added and the result is cast back to my::complex. I am assuming that the compiler can optimize any actual copying away.
However, the following does not work:
c1 = 2*(c2+c3)
since std::complex can not be multiplied by an integer (same problem if I multiply by a double and have complex<float>s).
I thought "ok, it seems that I have to add operator+ after all", but if I do that, I get use of overloaded operator '+' is ambiguous since the compiler can between std::complex and my::complex implicitly.
Is there a better way to achieve what I want or do I need to completely reimplement everything in std::complex and throw out the inheritance?
Adding these overloads as free functions is probably about as good a way to do the job as any. I wouldn't, however, write a separate one hard-coded for each possible pair of operand types--that would get tedious very quickly.
Instead, you undoubtedly want to write a template function to handle any pair of operand types. Something on this general order:
template <class T, class U>
auto operator*(T const &a, U const &b) -> typename std::common_type<T, U>::type
{
// code to produce the equivalent of: return a * b;
}
This way if you multiply a complex<double> by an int and a complex<float> by a double (etc.) you don't have to duplicate the function for each possible combination (and if you try to combine two types that don't have a common type such as complex<double> and std::string, it simply won't compile).
In this case, filling in the body is fairly simple: we have inputs of two different types, but we know (or can deduce) a common type that's compatible with both. We want to cast each input to that common type, and do the operation on the results from casting:
template <class T, class U>
auto operator*(T const &a, U const &b) -> typename std::common_type<T, U>::type
{
using ret_type = typename std::common_type<T, U>::type;
return ret_type(a) * ret_type(b);
}
For adding complex numbers of different types and other operators I would use free functions
std::complex<double> operator? (std::complex<double> a,std::complex<float> b){
std::complex<double> result;
// implement ?
return result;
}
std::complex<double> operator? (std::complex<float> a,std::complex<double> b){
return b ? a;
}
where ? is a placehold for the operator you want to have. Note that this is a pre-C++11 solution, for a much nicer way see Jerry Coffins answer.
For adding a number to a complex, like in 1+c, I would not make the effort to write an operator, but simply use c+1 instead (actually I am not sure if this works for std::complex but I would be surprised if not).
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