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<double> a(a0, 3);

std::complex<double> z(1,2);

std::valarray<std::complex<double> > 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<std::complex<double> >& operator*(double scalar, const

std::valarray<std::complex<double> > &v)

{

return std::complex<double>(scalar) * v;

}

std::valarray<std::complex<double> >& operator*(const

std::valarray<std::complex<double> > &v, double scalar)

{

return std::complex<double>(scalar) * v;

}

Thanks, that works with some adaptation. I wanted to multiply

complex<T> * valarray<T>; the above defines T * valarray<complex<T> > (T

being double). So if insert the adapted code

std::valarray<std::complex<double> >& operator*

(std::complex<double> scalar,

const std::valarray<double> &v)

{

return std::complex<double>(scalar) * v;

}

my program compiles. I can make it a little more generic,

template<class T>

std::valarray<std::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<complex> and

valarray<complex> * 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<typename _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