1

In my program, I use many arma::uvecs, and check equality between them like this

#include <armadillo>
using Vec = typename arma::uvec;
Vec v1({0, 0});
Vec v2({0, 1});
bool are_equal = arma::all(v1 == v2);

as I couldn't find any better equality operator in the Armadillo docs. Now that works perfectly fine, but to save some space, and as an exercise in subclassing and operator overloading, I want to define the equality sign directly between the vectors like this:

class Vec : public arma::uvec {
    friend bool operator==(const Collapsed& lhs, const Collapsed& rhs) {
        return arma::all(lhs == rhs);
    }
};

But sadly, I can't get it to work like that. I'm grateful about any hints!

gitchhiker
  • 161
  • 8
  • 1
    Your implemetation would work fine I think if you don't put it in a subclass, but as a global function instead. It looks to me like you misunderstand what `friend` does. – perivesta Apr 13 '21 at 11:02
  • Thanks! Truth is: I don't understand what `friend` does *at all*. It didn't work without it, and then I got the hint to prepend `friend` by a friend (no pun intended). – gitchhiker Apr 13 '21 at 11:08
  • Ah ok, well `friend` is not used to implement functions. I put some links in my answer – perivesta Apr 13 '21 at 11:17

2 Answers2

2

Operator overloads do not need to be part of a class. I would suggest implementing your comparison operator as a free function like this:

bool operator==(const arma::uvec& lhs, const arma::uvec& rhs) {
    return arma::all(lhs == rhs);
}

Regarding the friend in your question: As a quick summary, it provides the function that is befriended access to private and protected members of the class where the friend declaration is located. It it is not used to implement functions. You can read more about it on cppreference or on this SO question

EDIT Since the above only works if operator== is not already defined, here is a version that overrides it's implementation for a custom subclass:

class Vec : public arma::uvec
{
public:
    bool operator==(const Vec& other)
    {
        // depending on wether arma implemets operator== as member or free function
        // return arma::all(this->arma::uvec::operator==(other));
        return arma::all(arma::operator==(*this, other));
    }

};
perivesta
  • 3,417
  • 1
  • 10
  • 25
  • Actually, it throws an `error: no matching function for call to 'all'`, as I assess it because we use the very `==` operator between the two objects we're defining it for, inside its own definition. Is there some other operator we could use, or can we redefine it w/o using it? – gitchhiker Apr 13 '21 at 12:02
  • 1
    `lhs == rhs` inside an `operator==` is clearly a recursion. Some casting is needed to force use of different overload of operator. – Marek R Apr 13 '21 at 12:04
  • 1
    Ah yes I didn't think about that. In that case we can define the operator for your own `Vec` class. That needs to be a subclass now instead of an alias. – perivesta Apr 13 '21 at 12:07
  • Actually, we need to inherit the constructor, too. So far I couldn't figure how to adapt that from [this SO post](https://stackoverflow.com/questions/347358/inheriting-constructors) – gitchhiker Apr 13 '21 at 12:33
  • does putting `using uvec::uvec;` not work for inheriting the constructor? – perivesta Apr 13 '21 at 12:45
  • Yes, `using arma::uvec::uvec;` works, but both your uses of `arma::all` throw me an `error: no member named 'operator==' in 'arma::Col'` and an `error: no matching function for call to 'operator=='` for the first resp. second option you provided. – gitchhiker Apr 13 '21 at 13:13
1

Problem is library itself:

Armadillo: C++ library for linear algebra & scientific computing

operators:  +  −  *  %  /  ==  !=  <=  >=  <  >  &&  ||

  • Overloaded operators for Mat, Col, Row and Cube classes

  • Operations:
    + addition of two objects

    subtraction of one object from another or negation of an object

    * matrix multiplication of two objects; not applicable to the Cube class unless multiplying by a scalar

    % element-wise multiplication of two objects (Schur product)

    / element-wise division of an object by another object or a scalar

    == element-wise equality evaluation of two objects; generates a matrix/cube of type umat/ucube

    != element-wise non-equality evaluation of two objects; generates a matrix/cube of type umat/ucube

and uvec is:

uvec = ucolvec = Col<uword>

so operator== is already there and its functionality is strange/unexpected.

My recommendation is: do not fight with a library. Do not try provide own operator. Just provide a named function areEqual.

Defining a class just to provide own equal operator is not a best choice and if doing that then IMO it is better to use composition not inheritance (depending on requirement it will be more boiler plate code in class itself, but it will be easier to avoid unexpected behaviors).

Marek R
  • 32,568
  • 6
  • 55
  • 140