1

The error I receive:

/usr/include/c++/7/bits/stl_function.h:386: 
error: no operator "<" matches these operands
operand types are: const QVector3D < const QVector3D
{ return __x < __y; }

I'm using QVector3D with std::set and std::hypot. Is there any approach to implement an overloaded operator< for QVector3D to be able to use it in my code?

std::pair<QVector3D, QVector3D> NearestNeighbor::nearest_pair(std::vector<QVector3D> points)
{
     // // Sort by X axis
     std::sort( points.begin(), points.end(), [](QVector3D const &a, QVector3D const &b) { return a.x() < b.x(); } );

     // // First and last points from `point` that are currently in the "band".
     auto first = points.cbegin();
     auto last = first + 1;

     // // The two closest points we've found so far:
     auto first_point = *first;
     auto second_point = *last;

     std::set<QVector3D> band{ *first, *last };

     // // Lambda function to find distance
     auto dist = [] (QVector3D const &a, QVector3D const &b) { return std::hypot(a.x() - b.x(), a.y() - b.y()); };

     float d = dist(*first, *last);

     while (++last != points.end()) {
         while (last->x() - first->x() > d) {
             band.erase(*first);
             ++first;
         }

         auto begin = band.lower_bound({ 0, last->y() - d, 0 });
         auto end   = band.upper_bound({ 0, last->y() + d, 0 });

         assert(std::distance(begin, end) <= 6);

         for (auto p = begin; p != end; ++p) {
             if (d > dist(*p, *last)) {
                 first_point = *p;
                 second_point = *last;
                 d = dist(first_point, second_point);
             }
         }

         band.insert(*last);
     }
     return std::make_pair(first_point, second_point);
}

UPDATE

With @CuriouslyRecurringThoughts help, the problem solved by replacing:

std::set<QVector3D> band{ *first, *last };

with:

auto customComparator = [](QVector3D const &a, QVector3D const &b) { return a.y() < b.y(); };
std::set<QVector3D, decltype (customComparator)> band({ *first, *last }, customComparator);

Also I can do this:

auto customComparator = [](QVector3D const &a, QVector3D const &b) { return a.y() < b.y(); };
std::set<QVector3D, decltype (customComparator)> band(customComparator);
band.insert(*first);
band.insert(*last);
Megidd
  • 7,089
  • 6
  • 65
  • 142
  • 2
    [Why yes you can!](https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading) But you need to figure out what < means for a `QVector3D` and it must allow [Strict weak ordering](https://en.wikipedia.org/wiki/Weak_ordering) – user4581301 Jul 06 '19 at 05:35

1 Answers1

1

I think you have various possibilities. Yes, you can overload operator< as stated in the comment, but I would advise against it: you need a particular comparison function for this particular usecase, maybe somewhere else you'll need a different ordering. Unless the ordering relationship for a type is obvious I would suggest avoiding overloading the operator.

You can provide a custom comparison function, like in the following

auto customComparator = [](QVector3D const &a, QVector3D const &b) { return a.x() < b.x(); };

std::set<QVector3D, decltype(customComparator)> set(customComparator);

set.insert(*first)

To me it is unclear what the band set is trying to achieve, but since you are invoking upper and lower bound on the y()coordinate, maybe you want to compare on y() but this mean that two points having the same y() will be considered equal and std::set does not allow duplicates.

Otherwise, you can look into std::unordered_set (https://en.cppreference.com/w/cpp/container/unordered_set) which does not require ordering, but only that the element have operator == and an hash function.

Edit: another alternative: you can use std::vectorand then use the free function std::lower_bound and std::upper_bound with custom compare function, see https://en.cppreference.com/w/cpp/algorithm/lower_bound

  • Thanks =) You are using `myCoord`, I wonder how `myCoord` is declared. – Megidd Jul 06 '19 at 07:27
  • 1
    Apologies, myCoord was a type I created in a compiler to make sure that my syntax on the set was correct and I was too lazy to install Qt – CuriouslyRecurringThoughts Jul 06 '19 at 07:28
  • I guess `myCoord` could be an alias for `QVector3D` right? – Megidd Jul 06 '19 at 07:29
  • Thanks for clarification =) I didn't use `set.insert` in my code. Instead, I just did `std::set band{ *first, *last };` I wonder what is the equivalent statement after implementing your suggestion. – Megidd Jul 06 '19 at 07:35
  • Oh, I got it, I just did: `std::set band(customComparator);` and then I did: `band.insert(*first); band.insert(*last);` – Megidd Jul 06 '19 at 07:40
  • 1
    Or you can also do something like: std::set set({*first, *last}, op); See the available ctors of std::set at https://en.cppreference.com/w/cpp/container/set/set – CuriouslyRecurringThoughts Jul 06 '19 at 07:42