开发者

C++, comparator, pointer to function

I would like to create sorted set of points according to x or y coordinates.

typedef std::set <Point2D, sorter> Points;

For the type of "Point" I would like to use a different comparators. The first one sorts points according to the x coordinates, the second one according to the y coordinates:

typedef std::set <Point2D, sortPointsByX()> Points;
typedef std::set <Point2D, sortPointsByy()> Points;

where

class sortPoints2DByX
{
    public:

            bool operator() ( const Point2D &p1, const Point2D &p2 );

};

class sortPoints2DByY
{
    public:

            bool operator() ( const Point2D &p1, const Point2D &p2 );

};

Is it poss开发者_开发百科ible to create a pointer to the constructor sortPoints2DByX/sortPoints2DByY classes in Points declaration

typedef std::set <Point2D, pointer_to_somparator_class> Points;

and by the need to use any of them?

I need to have one data type can be sorted in two ways.

If this idea is wrong, is there any more suitable solution?

I need to compute median of x and y coordinates...

Thanks for your help...


Is it possible to create a pointer to the constructor sortPoints2DByX/sortPoints2DByY classes in Points declaration?

No, you cannot take the address a class' constructor.

I need to have one data type can be sorted in two ways.

You can get around using pointers to functions. Example implementation:

#include <algorithm>
#include <set>
#include <iostream>

    // Your implementation may differ.
struct Point
{
    int x; int y;
    Point(int x_, int y_)
        : x(x_), y(y_) {}
};

    // For display purposes.
void print(const Point& point)
{
    std::cout << '(' << point.x
        << ',' << point.y << ')' << std::endl;
}

bool OrderByX ( const Point& lhs, const Point& rhs )
{
    return (lhs.x < rhs.x);
}

bool OrderByY ( const Point& lhs, const Point& rhs )
{
    return (lhs.y < rhs.y);
}

    // Type of comparison operator.
typedef bool(*Comparator)
    (const Point&lhs,const Point&rhs);

    // Set used to store points in sorted order.
typedef std::set<Point, Comparator> Points;

int main ( int, char ** )
{
        // Each set ordered with it's own criteria.
    Points by_x(&OrderByX);
    Points by_y(&OrderByY);

        // Insert each point in both sets.
    by_x.insert(Point(1,2)); by_y.insert(Point(1,2));
    by_x.insert(Point(3,1)); by_y.insert(Point(3,1));
    by_x.insert(Point(4,3)); by_y.insert(Point(4,3));
    by_x.insert(Point(2,4)); by_y.insert(Point(2,4));

        // Show that 1st set is in proper order.
    std::cout << "Sorted by X:" << std::endl;
    std::for_each(by_x.begin(), by_x.end(), &print);
    std::cout << std::endl;

        // Show that 2nd set is in proper order.
    std::cout << "Sorted by Y:" << std::endl;
    std::for_each(by_y.begin(), by_y.end(), &print);
    std::cout << std::endl;
}

It generates the following output:

Sorted by X:
(1,2)
(2,4)
(3,1)
(4,3)

Sorted by Y:
(3,1)
(1,2)
(4,3)
(2,4)


I have two solutions, both of which have been tested:

First, code common to both:

class Point2D {
 public:
   Point2D(int x, int y) : x_(x), y_(y) { }

   int getX() const { return x_; }
   int getY() const { return y_; }

 private:
   int x_, y_;
};

And the main function...

int main(int argc, char *argv[])
{
   Points s1(compareByX);
   Points s2(compareByY);
   const int size = 1750;

   for (int x = -size; x <= size; ++x) {
      for (int y = -size; y <= size; ++y) {
         Point2D p(x, y);
         s1.insert(p);
         s2.insert(p);
      }
   }
   return 0;
}

Now, for solution 1:

#include <tr1/functional>
#include <set>

typedef ::std::tr1::function<bool (const Point2D &, const Point2D &)> comparefunc_t;
typedef ::std::set <Point2D, comparefunc_t> Points;

bool compareByX(const Point2D &a, const Point2D &b)
{
   return (a.getX() != b.getX()) ?
      (a.getX() < b.getX()) : (a.getY() < b.getY());
}

bool compareByY(const Point2D &a, const Point2D &b)
{
   return (a.getY() != b.getY()) ?
      (a.getY() < b.getY()) : (a.getX() < b.getX());
}

And the much longer solution 2:

class Point2DComparator {
 public:
   virtual bool operator()(const Point2D &a, const Point2D &b) const = 0;

 protected:
   const Point2DComparator &operator =(const Point2DComparator &b) {
      return *this;
   }
   Point2DComparator(const Point2DComparator &b) { }
   Point2DComparator() { }
};

class Point2DComparatorEnvelope : public Point2DComparator {
 public:
   Point2DComparatorEnvelope(const Point2DComparator &letter)
        : letter_(letter)
   {
   }

   virtual bool operator()(const Point2D &a, const Point2D &b) const {
      return letter_(a, b);
   }

 private:
   const Point2DComparator &letter_;
};

class XComparator : public Point2DComparator {
 public:
   virtual bool operator() ( const Point2D &a, const Point2D &b) const {
      return (a.getX() != b.getX()) ?
              (a.getX() < b.getX()) : (a.getY() < b.getY());
   }
};

class YComparator : public Point2DComparator {
 public:
   virtual bool operator() ( const Point2D &a, const Point2D &b) const {
      return (a.getY() != b.getY()) ?
              (a.getY() < b.getY()) : (a.getX() < b.getX());
   }
};

typedef ::std::set<Point2D, Point2DComparatorEnvelope> Points;
XComparator compareByX;
YComparator compareByY;

They seem virtually (no pun intended) identical in performance. The second is much more complex, though if you peer at the internals of ::std::tr1::function you will see that it is extremely hairy. The second is mainly useful for demonstration purposes. IMHO, the standard is broken for requiring the stupid envelope/letter hack for the whole thing to work.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜