2

I think that the default overload of == for valarray is not very convenient. By default x==y (for two valarrays x and y) returns a valarray<bool>, with true on the ith entry if x[i]==y[i]. Rather, I need a single bool, which tells me if both valarray<double> contain the same elements or not. I know I can do this with a cycle, but having to do the cycle every time is not convenient. What's the best workaround here? Is there a way for me to define my own overload of == (and also !=, <, and so on)?

a06e
  • 18,594
  • 33
  • 93
  • 169

4 Answers4

3

"Not very convenient"? This behaviour is exactly the reason for valarray.

To override it would be entirely self-defeating.

If you don't like it, just use a vector instead.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • I like how `x+y` works for `valarray`, and I couldn't do that if I used `vector`. But I think `x==y` should return a single `bool`. Is there a way to modify just `==` (and the other comparisons)? – a06e Jun 29 '15 at 21:28
  • @becko: Hum just write a simple function to do it? – Lightness Races in Orbit Jun 29 '15 at 21:29
  • `+` was just an example. I also want `-`, `*`, and so on. Moreover, I know that `valarray` has contrived versions of these operators which are more efficient than a naive implementation (I think they use proxy classes to store intermediate results in expressions like `x + y + z` and then evaluate the whole expression together). I would like to take advantage of those. – a06e Jun 29 '15 at 21:31
1

Do not override the default operator== use for example this instead:

bool isEqual( const std::valarray< bool >& aResult )
{
    bool equals = true;
    for ( auto item : aResult )
    {
        equals &= item;
    }
    return equals;
}

And then use it:

std::valarray< int > x;
std::valarray< int > y;

bool equals = isEqual( x == y );
p.i.g.
  • 2,815
  • 2
  • 24
  • 41
  • If I can (can I? how?) override the default `operator==`, why not do it? That would be clearer to read than `isEqual(x==y)`. – a06e Jun 29 '15 at 21:41
  • @becko because the operator is alredy doing half of what you need. On the other hand, if `x!=y` then not all elements have to be compared. Would be interesting to see what would be faster. – 463035818_is_not_an_ai Jun 29 '15 at 21:49
  • @tobi303 both `x==y` and `x!=y` can short-circuit (which would be easy to fix in this answer). – a06e Jun 29 '15 at 21:50
  • @becko I did not mean the operator `!=` but the evaluation of `==` in case x is not equal to y. Of course the same works for `!=`. – 463035818_is_not_an_ai Jun 29 '15 at 21:52
  • @becko as I understand it, in the answer all elements are compared (by the built-in `x==y`). He only shortcircuits the AND of all this results while one could already short-circuit the comparison of the elements (but this would require not to use the built-in `==`) – 463035818_is_not_an_ai Jun 29 '15 at 21:58
  • There can be an `if` in the `for` loop if you like it better. And if the item is false just return false. – p.i.g. Jun 29 '15 at 22:00
  • @p.i.g. Yes, that's what I meant. – a06e Jun 30 '15 at 14:28
  • @p.i.g. yes, you can do that, but then you still compare all elements of the valarrays (before you even enter the loop), which is not the most efficient way. – 463035818_is_not_an_ai Jun 30 '15 at 17:42
1

I agree with the others not to override the == operator. The reason is that those operators are the major reason to use a valarray. If you do not need element-wise operators simply do not use valarray. Also you might need the original version of the operator at some point so why would you throw it away?

I like p.i.g s solution, but if efficiency is a major concern, I would modify it like this:

#include <utility>
#include <valarray>

template <typename T>
bool isEqual( const std::valarray<T>& x,const std::valarray<T>& b) {
    bool equals = true;

    for (auto it = std::make_pair(std::begin(x), std::begin(b));it.first != std::end(x);++it.first,++it.second) {
        equals &= ((*it.first) == (*it.second));
        if (!equals) break;
    }
    return equals;
}

and use it like this

valarray<T> x,y;
bool b = isEqual(x,y);

By not using the built-in == not all elements in the valarrays have to be compared.

PS:

+ was just an example. I also want -, *, and so on. Moreover, I know that valarray has contrived versions of these operators which are more efficient than a naive implementation (I think they use proxy classes to store intermediate results in expressions like x + y + z and then evaluate the whole expression together). I would like to take advantage of those.

Actually, thats interesting and I didnt know about this before. And the conclusion should be: Do not override those operators, otherwise you cannot take advantage of their clever implementations.

pcarter
  • 1,516
  • 14
  • 21
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
0

If you are decided on "overriding" std::valarray's operator== for commodity (instead of writing a named function like in user463035818's answer), you could write a custom "adaptor" class:

template<typename T>
class CustomValArray : public std::valarray<T> {
public:
    typedef std::valarray<T> base;
    // We need to re-implement any non-default constructors we want to use:
    CustomValArray(std::initializer_list<T> init) : base(init) {}
};

/// Accumulation (single bool) comparison 
template<typename T>
bool operator==(const CustomValArray<T> &lhs, const CustomValArray<T> &rhs) {
    return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
}

If you also wanted to be able to use the original operator== for std::valarray, you could do so by writing a named function:

/// Element-wise comparison
template<typename T>
auto elementWiseEqual(const CustomValArray<T> &lhs, const CustomValArray<T> &rhs)  {
    // We delegate to operator==(const std::valarray<T> &, const std::valarray<T> &)
    typedef std::valarray<T> base;
    return dynamic_cast<const base &>(lhs) == dynamic_cast<const base &>(rhs);
}

Note: the snippet above uses C++14's automatic return type deduction. If you're on C++11, you should add something like -> decltype(std::valarray<T>() == std::valarray<T>()) to the end of the declarator.

Try it here.

If you choose to do it like this, inheriting directly from std::valarray, be aware of the possible risks of inheriting from an STL class.


As an alternative, you could have a wrapper class with a std::valarray<T> private member, and manually delegate any member functions you want to use to std::valarray.

Anakhand
  • 2,838
  • 1
  • 22
  • 50