I hope to create a static bool template function that multiple classes may use. I am using this function as a comparator to sort a vector of points. This is what i've done so far:
class.h
class Point2D
{
protected:
int x;
int y;
public:
int getX();
int getY();
Point2D();
Point2D(int x, int y);
template< typename T>
T sortAscending(T a, T b )
{
return a.getX() < b.getX();
}
static bool sortAscending(Point2D a, Point2D b);
}
Inside main.cpp
// my vector contains objects of Point2D that i wish to
//sort according to the value of x coordinates.
sort(p2Vec.begin(),p2Vec.end(),Point2D::sortAscending);
Gives me error:
error: no matching function for call to
‘sort(std::vector::iterator, std::vector::iterator,
)’
Does anyone know what i am doing wrong?
Use a lambda function here like following :
std::sort(p2Vec.begin(),p2Vec.end(),
[](const Point2D & p1, const Point2D & p2) {
return Point2D::sortAscending( p1, p2);
});
See here
Syntax would be:
std::sort(p2Vec.begin(), p2Vec.end(), &Point2D::sortAscending<Point2D>);
and requires the method to be static.
But better create a struct outside:
struct LessByGetX
{
template <typename T>
bool operator () (const T& lhs, const T& rhs) const
{
return lhs.getX() < rhs.getX();
}
};
and use it:
std::sort(p2Vec.begin(), p2Vec.end(), LessByGetX{});
Alternatively, you might use directly lambda:
std::sort(p2Vec.begin(), p2Vec.end(), [](const T& lhs, const T& rhs)
{
return lhs.getX() < rhs.getX();
});
Related
How do i fix this?
I'm getting error: 'this' argument has type const but function is not marked const c++ overload operator
template <class T>
class Rational {
private:
T n = 0;
T d = 1;
public:
Rational() = default;
T numerator() {
return n;
}
T denominator() {
return d;
}
};
template <class T>
inline bool const operator ==(const Rational <T> & lhs, const Rational <T>& rhs) {
return lhs.numerator() * rhs.denominator() == lhs.denominator() * rhs.numerator();
}
My guess is that numerator() and denominator() member functions are not const member functions. Make them const. After that, the above function should work.
BTW, there is no need for the return type to be bool const. Keep it simple and change it to bool.
If numerator() and denominator() are to be used to directly assign to Rationals internal member variables as well as being used in const contexts, you need two sets of overloads. One mutable and one const:
// mutable interface
T& Rational::numerator();
T& Rational::denominator();
// const interface if T may only be a fundamental integral type
T Rational::numerator() const;
T Rational::denominator() const;
// const interface if sizeof(T) may be > sizeof(T*)
T const& Rational::numerator() const;
T const& Rational::denominator() const;
Note, only one of the const interfaces may be used so you need to select one of them.
Here's an example of how it can be done:
#include <iostream>
#include <type_traits>
template<typename T>
class Rational {
public:
// pass by value for fundamental types, by const& for other types
using by_value_or_by_const_ref =
std::conditional_t<std::is_fundamental_v<T>, T, T const&>;
Rational(by_value_or_by_const_ref n, by_value_or_by_const_ref d) :
m_numerator(n), m_denominator(d) {}
// mutable interface
T& numerator() { return m_numerator; }
T& denominator() { return m_denominator; }
// const interface
by_value_or_by_const_ref numerator() const { return m_numerator; }
by_value_or_by_const_ref denominator() const { return m_denominator; }
private:
T m_numerator;
T m_denominator;
};
template<class T>
inline bool operator==(const Rational<T>& lhs, const Rational<T>& rhs) {
// using const interface
return lhs.numerator() * rhs.denominator() ==
lhs.denominator() * rhs.numerator();
}
int main() {
Rational<int> a(10, 20);
Rational<int> b(10, 10);
// using mutable interface
a.denominator() /= 4;
b.numerator() *= 2;
std::cout << std::boolalpha << (a == b) << "\n";
}
According to boost documentation - proper usage of boost::operators is to derive from it:
class A : boost::operators<A>
{
public:
bool operator < (const A&) const { return false; }
};
Now, I can use > and <= and >= because all of these operators can be implemented with <, see code snippet from boost:
template <class T, class B = operators_detail::empty_base<T> >
struct less_than_comparable1 : B
{
friend bool operator>(const T& x, const T& y) { return y < x; }
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); }
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
};
And finally less_than_comparable1 is one of boost::operators base class.
PROBLEM:
But adding such inheritance is not always convenient. E.g. this inheritance means I have to add constructor(s) to some structs, otherwise all old code, such as A{1} stops compiling:
struct A : boost::operators<A>
{
A() = default;
A(int a, int b = 0) : a(a), b(b) {}
int a;
int b;
};
bool operator < (const A&, const A&);
I tried several ways: inner class, static members of boost::operators<A> but it seems that only inheritance works.
I accept an answer that shows the way how to use boost::operators without inheritance.
I can also accept an answer, that explains why this inheritance is needed.
Ok, let's simplify a little this example, why I need inheritance in this very example below to get operator > from operator <?
template <typename A>
struct GtOperator
{
friend bool operator > (const A& l, const A& r)
{
return r < l;
}
};
struct A : private GtOperator<A>
{
bool operator < (const A&) const
{
return false;
}
};
int main() {
if (A{} > A{})
{
return -1;
}
}
Nothing else seems to work, e.g. this way does not work:
struct A
{
GtOperator<A> dummy;
bool operator < (const A&) const
{
return false;
}
};
Is it possible not to inherit from boost::operators, but still use it?
No, basically. It's intended to be inherited from. The reason it works is because argument-dependent lookup will only look for friend functions and function templates in associated classes ([basic.lookup.argdep]/4) - which are going to be A and A's base classes. If boost::operators<A> isn't a base class of A, its friend functions won't be found by name lookup.
Even with new aggregate initialization rules in C++17, A{1,2} would break because you'd have to write A{{},1,2}.
Your best bet is probably to write a macro that functions as a mixin that effectively accomplishes the same thing. So the ordering ones would be:
#define LESS_THAN_COMPARABLE(T) \
friend bool operator>(const T& x, const T& y) { return y < x; } \
friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); } \
friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
class A
{
public:
bool operator < (const A&) const { return false; }
LESS_THAN_COMPARABLE(A)
};
Yes, that kind of sucks. (Also these could be defined as non-member functions as well, just drop the friend and put the macro invocation outside of the class).
The other alternative, besides adding constructors and writing macros, is to hope that <=> comes to fruition and then wait a few years to be able to use it.
I would like to write a wrapper class around STL heaps that allows the user to provide their own comparator. I would like to have the comparators be functors so that they may close over some state.
For example, consider maintaining a sorted list of 2D points. The sorting criterion is distance from a given point. I'd like to provide a default comparator that sorts based on distance from the origin, but also give the user the option to compare based on distance from an arbitrary point.
My problem is: I don't know how to properly structure the functor inheritance to make this work in a flexible manner. Here is the sorted points example to illustrate what I want:
struct Point {
int x, y;
Point(int xx, int yy) : x(xx), y(yy) {}
static float dist(const Point &a, const Point &b) {
const int dx = a.x - b.x, dy = a.y - b.y;
return sqrtf(dx*dx + dy*dy);
}
};
// Abstract Point comparison base class.
class Comparator {
public:
virtual bool operator()(const Point& lhs, const Point& rhs) = 0;
};
// Sorts Points according to distance from the origin.
class DefaultComparator : public Comparator {
public:
virtual bool operator()(const Point& lhs, const Point& rhs) {
const Point zero(0,0);
const float dl = Point::dist(zero, lhs), dr = Point::dist(zero, rhs);
return dl < dr;
}
};
// Sorts Points according to distance from a given Point.
class RelativeComparator : public Comparator {
public:
RelativeComparator(Point p) : _point(p) {}
virtual bool operator()(const Point& lhs, const Point& rhs) {
const float dl = Point::dist(_point, lhs), dr = Point::dist(_point, rhs);
return dl < dr;
}
private:
const Point _point;
};
class SortedPoints {
public:
SortedPoints(Comparator &comp) : _comp(comp) {}
void push(Point p) {
_points.push_back(p);
std::push_heap(_points.begin(), _points.end(), _comp);
}
bool pop(Point &p) {
if (_points.empty()) {
return false;
} else {
std::pop_heap(_points.begin(), _points.end(), _comp);
p = _points.back();
_points.pop_back();
return true;
}
}
private:
typedef std::vector<Point> PointList;
Comparator &_comp;
PointList _points;
};
int main() {
DefaultComparator defaultComp;
RelativeComparator relativeComp(Point(100,100));
SortedPoints list1 = SortedPoints(defaultComp);
SortedPoints list2 = SortedPoints(relativeComp);
Point p(0,0);
list1.push(Point(15,15));
list1.push(Point(13,13));
list1.push(Point(5,5));
printf("List one (relative to 0,0):\n");
while (list1.pop(p)) {
printf("%d,%d\n", p.x, p.y);
}
list2.push(Point(15,15));
list2.push(Point(13,13));
list2.push(Point(5,5));
printf("List two (relative to 100,100):\n");
while (list2.pop(p)) {
printf("%d,%d\n", p.x, p.y);
}
return 0;
}
Due to the way the inheritance is structured, I'm getting a compilation error when the STL heap implementation tries to instantiate a Comparator (because it's an abstract class). The precise error is:
sortedpoints.cpp: In member function ‘void SortedPoints::push(Point)’:
sortedpoints.cpp:51: error: cannot allocate an object of abstract type ‘Comparator’
sortedpoints.cpp:17: note: because the following virtual functions are pure within ‘Comparator’:
sortedpoints.cpp:19: note: virtual bool Comparator::operator()(const Point&, const Point&)
/usr/include/c++/4.2.1/bits/stl_heap.h: In function ‘void std::push_heap(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Point*, std::vector<Point, std::allocator<Point> > >, _Compare = Comparator]’:
sortedpoints.cpp:51: instantiated from here
/usr/include/c++/4.2.1/bits/stl_heap.h:203: error: cannot allocate an object of abstract type ‘Comparator’
sortedpoints.cpp:17: note: since type ‘Comparator’ has pure virtual functions
/usr/include/c++/4.2.1/bits/stl_heap.h: In function ‘void std::__adjust_heap(_RandomAccessIterator, _Distance, _Distance, _Tp) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Point*, std::vector<Point, std::allocator<Point> > >, _Distance = long int, _Tp = Point]’:
/usr/include/c++/4.2.1/bits/stl_heap.h:238: instantiated from ‘void std::__pop_heap(_RandomAccessIterator, _RandomAccessIterator, _RandomAccessIterator, _Tp) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Point*, std::vector<Point, std::allocator<Point> > >, _Tp = Point]’
/usr/include/c++/4.2.1/bits/stl_heap.h:265: instantiated from ‘void std::pop_heap(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Point*, std::vector<Point, std::allocator<Point> > >]’
sortedpoints.cpp:58: instantiated from here
What is the proper way to accomplish this sort of task? If my Comparator inheritance strategy is a bad one, I'd like to know that too: this is just the first method I tried.
If you look at the documentation for push_heap, you'll see that it takes the comparator by value, so it's going to try to copy your Comparator object.
template <class RandomAccessIterator, class Compare>
void push_heap (RandomAccessIterator first, RandomAccessIterator last,
Compare comp);
Instead of holding a reference to the Comparator object in SortedPoints, you could create a std::function object that matched the Comparator function signature and pass that into push_heap (or boost::function if you're stuck on C++03).
For your code, you could try something like this:
class SortedPoints
{
public:
typedef std::function<bool (const Point& lhs, const Point& rhs)> MyComparator; // <-- Add this typedef
SortedPoints(MyComparator comp) : _comp(comp) {} // <-- Use MyComparator instead of Comparator&
void push(Point p) {
_points.push_back(p);
std::push_heap(_points.begin(), _points.end(), _comp);
}
bool pop(Point &p) {
if (_points.empty()) {
return false;
} else {
std::pop_heap(_points.begin(), _points.end());
p = _points.front();
_points.pop_back();
return true;
}
}
private:
typedef std::vector<Point> PointList;
MyComparator _comp; // <-- Use MyComparator instead of Comparator&
PointList _points;
};
I figured out a way to do what I want using regular OOP paradigms. Using the C++11 functional features suggested by #pzed is a good idea, however the rest of my codebase is not C++11 and I'd like to stick with consistent paradigms.
The strategy is to have the base Comparator class close over a subclass instance, and simply pass through the comparison to the subclass.
For example, the three classes from above become:
class Comparator {
public:
Comparator(Comparator &c) : _comparator(c) {}
virtual bool operator()(const Point& lhs, const Point& rhs) {
return _comparator(lhs, rhs);
}
private:
Comparator& _comparator;
};
// Sorts Points according to distance from the origin.
class DefaultComparator : public Comparator {
public:
DefaultComparator() : Comparator(*this) {}
virtual bool operator()(const Point& lhs, const Point& rhs) {
const Point zero(0,0);
const float dl = Point::dist(zero, lhs), dr = Point::dist(zero, rhs);
return dl < dr;
}
};
// Sorts Points according to distance from a given Point.
class RelativeComparator : public Comparator {
public:
RelativeComparator(Point p) : Comparator(*this), _point(p) {}
virtual bool operator()(const Point& lhs, const Point& rhs) {
const float dl = Point::dist(_point, lhs), dr = Point::dist(_point, rhs);
return dl < dr;
}
private:
const Point _point;
};
And the rest of the code stays the same, for example we can now do:
RelativeComparator relativeComp(Point(100,100));
SortedPoints list1 = SortedPoints(relativeComp);
as before, and it works.
Hopefully this isn't considered an abuse of inheritance.
I got this working by making 3 changes:
Removed the polymorphism in favor of templates
Added the comparator to the pop_heap call as well.
Added const to the operator ()
I get this:
// Sorts Points according to distance from the origin.
class DefaultComparator {
public:
virtual bool operator()(const Point& lhs, const Point& rhs) const {
const Point zero(0, 0);
const float dl = Point::dist(zero, lhs), dr = Point::dist(zero, rhs);
return dl < dr;
}
};
// Sorts Points according to distance from a given Point.
class RelativeComparator {
public:
RelativeComparator(Point p) : _point(p) {}
virtual bool operator()(const Point& lhs, const Point& rhs) const {
const float dl = Point::dist(_point, lhs), dr = Point::dist(_point, rhs);
return dl < dr;
}
private:
const Point _point;
};
template <class C>
class SortedPoints
{
public:
SortedPoints(C &comp) : _comp(comp) {}
void push(Point p) {
_points.push_back(p);
std::push_heap(_points.begin(), _points.end(), _comp);
}
bool pop(Point &p) {
if (_points.empty()) {
return false;
}
else {
std::pop_heap(_points.begin(), _points.end(), _comp);
p = _points.front();
_points.pop_back();
return true;
}
}
private:
typedef std::vector<Point> PointList;
C &_comp;
PointList _points;
};
int main()
{
DefaultComparator defaultComp;
RelativeComparator relativeComp(Point(100, 100));
SortedPoints<DefaultComparator> list1 = SortedPoints<DefaultComparator>(defaultComp);
Point p(0, 0);
list1.push(Point(15, 15));
list1.push(Point(13, 13));
list1.push(Point(5, 5));
printf("List one (relative to 0,0):\n");
while (list1.pop(p)) {
printf("%d,%d\n", p.x, p.y);
}
SortedPoints<RelativeComparator> list2 = SortedPoints<RelativeComparator>(relativeComp);
list2.push(Point(15, 15));
list2.push(Point(13, 13));
list2.push(Point(5, 5));
printf("List two (relative to 100,100):\n");
while (list2.pop(p)) {
printf("%d,%d\n", p.x, p.y);
}
return 0;
}
I want to construct two priority queue that has different compare method(there are two reverse priority methods named cmp1 and cmp2)
My program can't go through the compiler check.Why does such error happen and is there any better solution?
#include <iostream>
#include <queue>
#include <string>
using namespace std;
struct item
{
string name;
string sex;
string id;
double score;
friend istream& operator >> (istream &is,item& data)
{
is>>data.name>>data.sex>>data.id>>data.score;
}
/*friend bool operator < (item& a,item& b)
{
return a.score<b.score;
}*/
};
struct cmp1{
operator bool()(item& x,item& y)
{
return x.score>y.score;
}
};
struct cmp2
{
operator bool()(item& x,item& y)
{
return x.score<y.score;
}
};
int main()
{
priority_queue<item,vector<item>,cmp1> boys;
priority_queue<item,vector<item>,cmp2>girls;
item temp;
int num;
cin>>num>>temp;
for(int i=0;i<num;i++)
{
if(temp.sex=="M")
boys.push(temp);
else
girls.push(temp);
}
return 0;
}
I'm going to take a wild guess at the problem.... your comparison functors are incorrect. Instead of overloading operator bool, you need to overload the function call operator, i.e.
struct cmp1{
bool operator()(const item& x, const item& y)
{
return x.score>y.score;
}
};
struct cmp2
{
bool operator()(const item& x, const item& y)
{
return x.score<y.score;
}
};
(Perhaps this was what you intended, but just got the syntax a little wrong?)
Actually, I think the best way to do it is to use std::less and std::greater. If you have overloaded operator< and operator> for your class, you can do it like this:
std::priority_queue<item, std::vector<item>, std::greater<item>> boys;
std::priority_queue<item, std::vector<item>, std::less<item>> girls;
That way you don't have to write the functor. Don't forget to #include <functional>.
Also, don't forget that the operators have to be overloaded taking const ref arguments (you can also take them by value, but that's not usually a good idea), and as const methods, like in:
bool operator<(const item& i) const {
return value < i.value;
}
bool operator>(const item& i) const {
return value > i.value;
}
Change your operator functions to this:
struct cmp1{
bool operator()(item& x,item& y)
{
return x.score>y.score;
}
};
struct cmp2
{
bool operator()(item& x,item& y)
{
return x.score<y.score;
}
};
You have defined the methods in the comparison classes wrong.
Try the following code:
struct cmp1{
bool operator()(item& x,item& y)
{
return x.score>y.score;
}
};
You have defined the methods as operator bool() ....
Also it is nice to add const to the parameters, as const item& x for showing that you won't change their values, as well a const at the end of the function definition:
bool operator()(const item& x, const item& y) const {...}
for showing that you won't change the member fields too.
I will write the third correct version of the predcate
struct cmp1
{
bool operator()( const item &x, const item &y ) const
{
return x.score > y.score;
}
};
struct cmp2
{
bool operator()( const item &x, const item &y ) const
{
return x.score < y.score;
}
};
class Point
{
int x;
}
static Point referencePoint;
struct Comparator
{
bool AbsComparator(const Point& p1, const Point& p2)
{
return abs(p1.x - referencePoint.x) < abs(p2.x - referencePoint.x);
}
};
list<Point> points;
points.sort(Comparator::AbsComparator);
But I CANNOT use a static referencePoint for multithreading safe, is there any other way??
Thanks.
Make it part of Comparator:
struct Comparator
{
Point referencePoint;
Comparator(Point referencePoint): referencePoint(referencePoint) {}
Comparator(const Comparator& rhs) {
referencePoint = rhs.referencePoint;
}
bool operator()(const Point& p1, const Point& p2) const
{
return abs(p1.x - referencePoint.x) < abs(p2.x - referencePoint.x);
}
};
...
points.sort(Comparator(refP));
Why not simply save the referencePoint or rather the integer value inside Point as a member inside your Comparator, that way you always access it in the comparator function.
Avoid global variables. That is start of writing multi-threaded code.
Use local variables instead:
Point referencePoint(10,20); //use local variable!
points.sort(Comparator(referencePoint));
Or simpy this,
points.sort(Comparator(Point(10,20)));
where Comparator is a functor defined as:
struct Comparator
{
Point referencePoint;
explicit Comparator(const Point & pt) : referencePoint(pt) {}
bool operator() (const Point& p1, const Point& p2) const
{
return abs(p1.x - referencePoint.x) < abs(p2.x - referencePoint.x);
}
};
You're done!
Notice the implementation of operator(). This makes the class a functor.
You can simply store this variable, either in a destructured or structured manner.
// destructured (only store what you need)
class ReferenceComparator {
public:
explicit ReferenceComparator(int x): _x(x) {}
explicit ReferenceComparator(Point const& p): _x(p.x) {}
bool operator()(Point const& left, Point const& right) const {
return abs(left.x - _x) < abs(right.x - _x);
}
private:
int _x;
}; // class ReferenceComparator
And then use it as:
list.sort(ReferenceComparator(myReferencePoint));
I would advise not using a list if you need sorting through. list are not good at it...