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.
 
         加载中,请稍侯......
 加载中,请稍侯......
      
精彩评论