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