I wrote:
I would like to multiply a valarray of doubles by a complex number and
get a valarray of complex numbers. Of course, a C++ compiler won't
jump to that conclusion; I need to define something to help it.
I didn't expect the following to compile:
#include <valarray>
#include <complex>
int main()
{
const double a0[] = {1.5, 4, 0};
std::valarray<d ouble> a(a0, 3);
std::complex<do uble> z(1,2);
std::valarray<s td::complex<dou ble> > c (3);
c = z * a; // error: no match for operator *
return 0;
}
Now the question is, what would be the clean way to provide such
functionality? I want to avoid putting any notational burden on the
user. If possible, I'd like to avoid code duplication. Is there a
"generic" approach?
red floyd replied (his/her corrections applied): How about simply providing an override on operator* ?:
std::valarray<s td::complex<dou ble> >& operator*(doubl e scalar, const
std::valarray<s td::complex<dou ble> > &v)
{
return std::complex<do uble>(scalar) * v;
}
std::valarray<s td::complex<dou ble> >& operator*(const
std::valarray<s td::complex<dou ble> > &v, double scalar)
{
return std::complex<do uble>(scalar) * v;
}
Thanks, that works with some adaptation. I wanted to multiply
complex<T> * valarray<T>; the above defines T * valarray<comple x<T> > (T
being double). So if insert the adapted code
std::valarray<s td::complex<dou ble> >& operator*
(std::complex<d ouble> scalar,
const std::valarray<d ouble> &v)
{
return std::complex<do uble>(scalar) * v;
}
my program compiles. I can make it a little more generic,
template<class T>
std::valarray<s td::complex<T> >& operator*(std:: complex<T> scalar,
const std::valarray<T > &v)
{
return std::complex<T> (scalar) * v;
}
(BTW, in the C++ lingo, that would be called (operator) overloading;
overriding means redefining an inherited virtual function in a derived
class.) But I see some drawbacks with this solution:
(A) *Genericity*
As you show, I'd have to define both real * valarray<comple x> and
valarray<comple x> * real. As alluded, I'll need the same pair for
complex * valarray<real>.
I'd need to type the same set for every operator (at least +, -, *, /).
When I want to use some other types besides complex, I'd have to repeat
everything for each such type. I think it should be possible to write a
template<class A, class B> and specify that A Op_ valarray<B> gives a
valarray<Larger _Of<A,B> >.
(B) *Efficiency*
Multiplying real * complex takes 2 multiplications (of real numbers).
By converting to the scalar to comples, we trade that in for 4
multiplications and 2 additions; this happens for every element of the
valarray.
Correct me if I'm mistaken, but it looks like this operator* creates a
temporary valarray, passing it by reference to the caller, which then
copies all the values into the receiving valarray. The standard library
seems to use closures to avoid such copying.
It's generally considered BAD to use preprocessor macros in C++. Can we
do without? It seems not even the standard templates can. In
<valarray>, I see this:
#define _DEFINE_BINARY_ OPERATOR(_Op, _Name) \
template<typena me _Tp> \
inline _Expr<_BinClos< _Name,_ValArray ,_ValArray,_Tp, _Tp>, _Tp> \
operator _Op (const valarray<_Tp> &__v, const valarray<_Tp> &__w) \
// [omitted 20 lines defining this and two other operators]
}
_DEFINE_BINARY_ OPERATOR(+, plus)
_DEFINE_BINARY_ OPERATOR(-, minus)
_DEFINE_BINARY_ OPERATOR(*, multiplies)
_DEFINE_BINARY_ OPERATOR(/, divides)
_DEFINE_BINARY_ OPERATOR(%, modulus)
_DEFINE_BINARY_ OPERATOR(^, _Bitwise_xor)
_DEFINE_BINARY_ OPERATOR(&, _Bitwise_and)
_DEFINE_BINARY_ OPERATOR(|, _Bitwise_or)
_DEFINE_BINARY_ OPERATOR(<<, _Shift_left)
_DEFINE_BINARY_ OPERATOR(>>, _Shift_right)
#undef _DEFINE_BINARY_ OPERATOR
Well, there's the answer to not having to retype everything for every
operator. And it gives the optimizations of a closure.
The question stays, is this a reasonable approach for my own types? Can
it be templated so it works for adding int to double just like for
multiplying complex<double> with double? Could this feat be achieved
without preprocessor macros?
Christian