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);
user3405291
  • 6,162
  • 5
  • 43
  • 115
  • 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