C ++ - 如何正确地将比较器传递给STL函数

时间:2016-12-13 20:25:22

标签: c++ c++11 stl

我写了一个PointCollection课程。

PointCollection拥有一堆积分。

它有2个成员函数。

addPoint(Point point)

findNearestKPoints(Point center, int k)

每次调用findNearestKPoints时,都会指定center来查找k周围最近的k点。

但它无法编译:

error: called object type 'bool (PointCollection::*)(const Point &, const Point &) const' is not a function or function pointer

如何正确地做到这一点?

我的代码作为参考:

struct Point {
    int val_;
    Point() {}
    Point(int val) : val_(val) {}
};

class PointCollection {
private:
    vector<Point> points_;
    Point center_;
public:
    PointCollection() {}
    virtual ~PointCollection() {}

    void addPoint(const Point &point) {
        points_.push_back(point);
    }

    bool compare(const Point &a, const Point &b) const {
        return std::abs(a.val_ - center_.val_) < std::abs(b.val_ - center_.val_);
    }

    vector<Point> findNearestKPoints(Point center, int k) {
        center_ = center;

        nth_element(points_.begin(), points_.begin() + k - 1, points_.end(), 
                    &PointCollection::compare);

        return vector<Point>(points_.begin(), points_.begin() + k);
    }
};

3 个答案:

答案 0 :(得分:8)

比较器是可调用对象。换句话说:函数指针或lambda闭包,或具有合适operator()的类。

&PointCollection::compare不是可调用对象。这是一种课堂方法。它不是可调用的对象,原因很简单,您无法直接调用它。只能在的实例上调用类方法。您必须在某处拥有此类的实例,并调用其compare()方法。它看起来像一个函数,但事实并非如此。这是一种课堂方法。

一个简单的解决方案是通过lambda捕获this,类似于(C ++ 14):

nth_element(points_.begin(), points_.begin() + k - 1, points_.end(),
              [this](const auto &a, const auto &b)
                  {
                      return this->compare(a, b);
                  });

lambda捕获thiscompare()可以在this上调用,就像可以直接从父方法调用一样。

P.S。您的findNearestKPoints()正在返回vector<Point>,而不是vector<int>,正如您所声明的那样。

答案 1 :(得分:1)

center是一个临时变量,不需要将其存储为成员变量。

最终版本:

class PointCollection {
private:
    vector<Point> points_;
public:
    PointCollection(vector<int> nums) {
        for (int num : nums) {
            points_.push_back({num});
        }
    }
    virtual ~PointCollection() {}

    void addPoint(const Point &point) {
        points_.push_back(point);
    }

    vector<Point> findNearestKPoints(Point center, int k) {
        nth_element(points_.begin(), points_.begin() + k - 1, points_.end(),
                    [&center] (const Point &a, const Point &b) {
                        return compare(a, b, center);
                    });

        return vector<Point>(points_.begin(), points_.begin() + k);
    }

    static bool compare(const Point &a, const Point &b, Point center) {
        return std::abs(a.val_ - center.val_) < std::abs(b.val_ - center.val_);
    }
};

答案 2 :(得分:1)

仿函数解决方案也很优雅,可以完成图片。

您可以在PointCollection类的内部(或外部)添加此仿函数:

struct compare {
    Point center_;
    bool operator()(const Point &a, const Point &b) const {
        return std::abs(a.val_ - center_.val_) < std::abs(b.val_ - center_.val_);
    }
 }

然后:

std::nth_element(points_.begin(), points_.begin() + k - 1, points_.end(), compare{center} );

优于lambda:在您想要使用它的地方实例化比较器(仿函数)更容易,更方便,而lambda需要重新编写(想象您还需要编写其他需要使用比较器的方法) ,即farthestK等...)