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 i
th 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)?
问题:
回答1:
"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.
回答2:
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 );
回答3:
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 <iostream>
#include <valarray>
template <typename T>
bool isEqual( const std::valarray<T>& x,const std::valarray<T>& b) {
using Iter = typename std::valarray<T>::const_iterator;
using IterP = std::pair<Iter,Iter>;
bool equals = true;
for (IterP it(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.
回答4:
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
.