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.
精彩评论