using C++ std::sort with lambda comparator - c++

I'm tryin to sort an array of objects using std::sort -
sort(convexHull.getSet(), convexHull.getSet()+convexHull.size(),
[](const Point & a, const Point & b) -> bool
{ if (a.getX() < b.getX())
return true;
else if (a.getX() == b.getX())
return a.getY() < b.getY();
else
return false;; }
);
where convexHull.getSet() returns a pointer to the beginning of an array.
as explained here.
But i'm getting a really long error from my compiler (Clion), something about my assignment operator -
#include <cmath>
#include <string>
using namespace std;
class Point
{
private:
int _x;
int _y;
double _arg;
void setArg()
{
if(sqrt(_x*_x + _y*_y) == 0)
_arg = 5;
else
_arg = _y / sqrt(_x*_x + _y*_y);
}
public:
Point () : Point(0, 0) {}
Point (const int x, const int y) : _x(x), _y(y)
{
setArg();
}
int getX () const
{ return _x; }
int getY () const
{ return _y; }
~Point () {}
Point& operator= (const Point &rval);
};
(where setArg simply computes a point angle from the positive x-axis).
i've tested the operator using this code -
Point p(5,5);
Point t(3,3);
t=p;
t.setXY(7,7);
and it seems to be working fine.
it's very long so i'll post just part of it -
In file included from /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/algorithm:62:0,
from /cygdrive/c/Users/o/Desktop/CPP/ex1/cppex1/ex1/ConvexHull.cpp:7:
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_algo.h: In instantiation of 'void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = const Point*; _Compare = __gnu_cxx::__ops::_Iter_comp_iter<main()::<lambda(const Point&, const Point&)> >]':
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_algo.h:1880:25: required from 'void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = const Point*; _Compare = __gnu_cxx::__ops::_Iter_comp_iter<main()::<lambda(const Point&, const Point&)> >]'
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_algo.h:1966:31: required from 'void std::__sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = const Point*; _Compare = __gnu_cxx::__ops::_Iter_comp_iter<main()::<lambda(const Point&, const Point&)> >]'
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_algo.h:4729:18: required from 'void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = const Point*; _Compare = main()::<lambda(const Point&, const Point&)>]'
/cygdrive/c/Users/o/Desktop/CPP/ex1/cppex1/ex1/ConvexHull.cpp:75:5: required from here
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/stl_algo.h:1847:17: error: passing 'const Point' as 'this' argument discards qualifiers [-fpermissive]
*__first = _GLIBCXX_MOVE(__val);
^
In file included from /cygdrive/c/Users/o/Desktop/CPP/ex1/cppex1/ex1/PointSet.h:9:0,
from /cygdrive/c/Users/o/Desktop/CPP/ex1/cppex1/ex1/ConvexHull.cpp:4:
/cygdrive/c/Users/o/Desktop/CPP/ex1/cppex1/ex1/Point.h:45:12: note: in call to 'Point& Point::operator=(const Point&)'
this might also be relevant -
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/predefined_ops.h:123:46: note: candidate: bool (*)(Point&, Point&) <conversion>
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/predefined_ops.h:123:46: note: conversion of argument 3 would be ill-formed:
/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/bits/predefined_ops.h:123:46: error: binding 'const Point' to reference of type 'Point&' discards qualifiers
/cygdrive/c/Users/o/Desktop/CPP/ex1/cppex1/ex1/ConvexHull.cpp:68:38: note: candidate: main()::<lambda(Point&, Point&)> <near match>
[](Point & a, Point & b) -> bool

Apparently the problem is not in the comparison but in what you are passing to std::sort. What is the declaration for
convexHull.getSet()
?
If that for example returns a const Point * then you have a const correctness problem because std::sort needs to be able to write to rearrange elements.

Related

Conversion Error when passing arguments to lambda comparator

I have a sorted vector of structures and I am trying to find the index of element that has the queried value in its member attribute. For this I am trying to use lower_bound, but I am having problems with the comparator lambda function. Here is a simplified version of my code:
#include <iostream>
#include <vector>
#include <algorithm>
struct Student
{
int id;
};
std::vector<Student> Students;
int main()
{
Student Ann = {1};
Student Bob = {3};
Student Alice = {4};
Students = {Ann, Bob, Alice};
int id_query = 3;
auto index_ptr = std::lower_bound(Students.begin(), Students.end(), id_query, [](const int a, const Student s) -> bool {return a < s.id;});
}
g++ with std=17 gives me the following
Starting build...
/bin/g++ -g /home/aram/dev/cpp/coverages/stack_overflow.cpp -std=c++17 -o /home/aram/dev/cpp/coverages/stack_overflow
In file included from /usr/include/c++/9/bits/stl_algobase.h:71,
from /usr/include/c++/9/bits/char_traits.h:39,
from /usr/include/c++/9/ios:40,
from /usr/include/c++/9/ostream:38,
from /usr/include/c++/9/iostream:39,
from /home/aram/dev/cpp/coverages/stack_overflow.cpp:1:
/usr/include/c++/9/bits/predefined_ops.h: In instantiation of ‘bool __gnu_cxx::__ops::_Iter_comp_val<_Compare>::operator()(_Iterator, _Value&) [with _Iterator = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >; _Value = const int; _Compare = main()::<lambda(int, Student)>]’:
/usr/include/c++/9/bits/stl_algobase.h:979:14: required from ‘_ForwardIterator std::__lower_bound(_ForwardIterator, _ForwardIterator, const _Tp&, _Compare) [with _ForwardIterator = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >; _Tp = int; _Compare = __gnu_cxx::__ops::_Iter_comp_val<main()::<lambda(int, Student)> >]’
/usr/include/c++/9/bits/stl_algo.h:2032:32: required from ‘_FIter std::lower_bound(_FIter, _FIter, const _Tp&, _Compare) [with _FIter = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >; _Tp = int; _Compare = main()::<lambda(int, Student)>]’
/home/aram/dev/cpp/coverages/stack_overflow.cpp:21:142: required from here
/usr/include/c++/9/bits/predefined_ops.h:177:11: error: no match for call to ‘(main()::<lambda(int, Student)>) (Student&, const int&)’
177 | { return bool(_M_comp(*__it, __val)); }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/9/bits/predefined_ops.h:177:11: note: candidate: ‘bool (*)(int, Student)’ <conversion>
/usr/include/c++/9/bits/predefined_ops.h:177:11: note: candidate expects 3 arguments, 3 provided
/home/aram/dev/cpp/coverages/stack_overflow.cpp:21:83: note: candidate: ‘main()::<lambda(int, Student)>’
21 | auto index_ptr = std::lower_bound(Students.begin(), Students.end(), id_query, [](const int a, const Student s) -> bool {return a < s.id;});
| ^
/home/aram/dev/cpp/coverages/stack_overflow.cpp:21:83: note: no known conversion for argument 1 from ‘Student’ to ‘int’
Build finished with error(s).
The terminal process failed to launch (exit code: -1).
The comparator of std::lower_bound is supposed to take the object dereferenced from the iterator, i.e. the element as the 1st parameter, the value to be compared as the 2nd parameter.
The type Type1 must be such that an object of type ForwardIt can be dereferenced and then implicitly converted to Type1. The type Type2 must be such that an object of type T can be implicitly converted to Type2.​
You need to change the order of the parameters, e.g.
auto index_ptr = std::lower_bound(Students.begin(), Students.end(), id_query, [](const Student s, const int a) -> bool {return s.id < a;});
LIVE

using lower_bound/upper_bound with 2 different types

I have a small working code for finding a range of items that uses a special compare method. But when I try to rewrite it with lower_bound() and upper_bound() function, I get a strange error. I have written a small code to show my problem. Here is the code:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
int main() {
string str = "banana";
string keyword = "ana";
int sa_idx[] = {5, 3, 1, 0, 4, 2};
vector<int> sa(sa_idx, sa_idx + sizeof(sa_idx) / sizeof(int) );
auto cmp = [&str] (const int &a, const string &keyword) -> bool
{
return strncmp(str.c_str() + a, keyword.c_str(), keyword.length()) < 0;
};
cout << (upper_bound(sa.begin(), sa.end(), keyword, cmp) -
lower_bound(sa.begin(), sa.end(), keyword, cmp)) << endl;
return 0;
}
As you see, compare function uses keyword and value of sa array for compare decision. A standard says:
The type Type1 must be such that an object of type ForwardIt can be
dereferenced and then implicitly converted to Type1. The type Type2
must be such that an object of type T can be implicitly converted to
Type2.
My compare function has int type for first argument(because of vector<int> of array) and string for the second argument type(as type of keyword). But I don't know why I get following error:
In file included from /usr/include/c++/6/bits/stl_algobase.h:71:0,
from /usr/include/c++/6/bits/char_traits.h:39,
from /usr/include/c++/6/ios:40,
from /usr/include/c++/6/ostream:38,
from /usr/include/c++/6/iostream:39,
from prog.cpp:1:
/usr/include/c++/6/bits/predefined_ops.h: In instantiation of ‘bool __gnu_cxx::__ops::_Val_comp_iter<_Compare>::operator()(_Value&, _Iterator) [with _Value = const std::__cxx11::basic_string<char>; _Iterator = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; _Compare = main()::<lambda(const int&, const string&)>]’:
/usr/include/c++/6/bits/stl_algo.h:2049:14: required from ‘_ForwardIterator std::__upper_bound(_ForwardIterator, _ForwardIterator, const _Tp&, _Compare) [with _ForwardIterator = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; _Tp = std::__cxx11::basic_string<char>; _Compare = __gnu_cxx::__ops::_Val_comp_iter<main()::<lambda(const int&, const string&)> >]’
/usr/include/c++/6/bits/stl_algo.h:2114:32: required from ‘_FIter std::upper_bound(_FIter, _FIter, const _Tp&, _Compare) [with _FIter = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; _Tp = std::__cxx11::basic_string<char>; _Compare = main()::<lambda(const int&, const string&)>]’
prog.cpp:19:57: required from here
/usr/include/c++/6/bits/predefined_ops.h:173:11: error: no match for call to ‘(main()::<lambda(const int&, const string&)>) (const std::__cxx11::basic_string<char>&, int&)’
{ return bool(_M_comp(__val, *__it)); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cpp:14:61: note: candidate: main()::<lambda(const int&, const string&)>
auto cmp = [&str] (const int &a, const string &keyword) -> bool
^~~~
prog.cpp:14:61: note: no known conversion for argument 1 from ‘const std::__cxx11::basic_string<char>’ to ‘const int&’
Have I missed something super obvious? Because it seems compiler looks for string as first argument of compare function.
Your problem here is that std::uppper_bound requires the cmp be of the signature
bool(T, decltype(*Iterator))
std::lower_bound has the opposite requirement though and wants
bool(decltype(*Iterator), T)
so you can't use the same comparator with both functions. There are other ways to modify the code but just adding a second comparator like
auto cmp1 = [&str](const string &keyword, const int &a) -> bool
{
return strncmp(keyword.c_str(), str.c_str() + a, keyword.length()) < 0;
};
auto cmp2 = [&str] (const int &a, const string &keyword) -> bool
{
return strncmp(str.c_str() + a, keyword.c_str(), keyword.length()) < 0;
};
cout << (upper_bound(sa.begin(), sa.end(), keyword, cmp1) -
lower_bound(sa.begin(), sa.end(), keyword, cmp2)) << endl;
allows the code to compile.

C++ std::sort a vector of share_ptr<objects>

How can I sort a vector of shared_ptrs C++? I'm trying to sort a vector a share_ptrs of struct data object. And the comparator function is also defined.
struct data{
int number;
};
bool comparator(const std::shared_ptr<data> &a, const std::shared_ptr<data> &b) {
return a->number < b->number();
}
int main() {
std::vector<std::shared_ptr<data>> v;
std::sort(v.begin(), v.end(), comparator);
}
But I got compile error:
In file included from /usr/include/c++/4.8/algorithm:62:0,
from test.cpp:10:
/usr/include/c++/4.8/bits/stl_algo.h: In instantiation of ‘void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::shared_ptr<data>*, std::vector<std::shared_ptr<data> > >; _Compare = bool (*)(const A&, const A&)]’:
/usr/include/c++/4.8/bits/stl_algo.h:2226:70: required from ‘void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::shared_ptr<data>*, std::vector<std::shared_ptr<data> > >; _Compare = bool (*)(const A&, const A&)]’
/usr/include/c++/4.8/bits/stl_algo.h:5491:55: required from ‘void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = __gnu_cxx::__normal_iterator<std::shared_ptr<data>*, std::vector<std::shared_ptr<data> > >; _Compare = bool (*)(const A&, const A&)]’
test.cpp:110:45: required from here
/usr/include/c++/4.8/bits/stl_algo.h:2159:29: error: invalid initialization of reference of type ‘const A&’ from expression of type ‘std::shared_ptr<data>’
.....
return a->number < b->number();
Must be:
return a->number < b->number;
However, I wonder if this is your real code and which compiler you are using. You should get much clearer error messages, for example:
Visual C++ 2013:
error C2064: term does not evaluate to a function taking 0 arguments
GCC v4.8.3:
error: expression cannot be used as a function
return a->number < b->number();
^
P.S.: You should post your complete code with all #includes when asking such questions. In your case, <vector>, <algorithm> and <memory>.

gcc compile-time error sorting vector in a namespace

The following MWE fails to compile on (Cygwin) gcc 4.8.3 but compiles on MSCV 2010
#include <vector>
#include <algorithm>
namespace Namespace
{
struct Bar
{
};
bool barComparator( Bar& bar1 , Bar& bar2 )
{
return true;
}
struct Foo
{
void doStuff()
{
std::vector<Bar> barVec;
std::sort( barVec.begin() , barVec.end() , barComparator );
}
};
}
int main()
{
};
gcc error message
In file included from /usr/lib/gcc/i686-pc-cygwin/4.8.3/include/c++/algorithm:62:0,
from Test007.cpp:2:
/usr/lib/gcc/i686-pc-cygwin/4.8.3/include/c++/bits/stl_algo.h: In instantiation of ‘_RandomAccessIterator std::__unguarded_partition(_RandomAccessIterator, _RandomAccessIterator, const _Tp&, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Namespace::Bar*, std::vector<Namespace::Bar> >; _Tp = Namespace::Bar; _Compare = bool (*)(Namespace::Bar&, Namespace::Bar&)]’:
/usr/lib/gcc/i686-pc-cygwin/4.8.3/include/c++/bits/stl_algo.h:2296:78: required from ‘_RandomAccessIterator std::__unguarded_partition_pivot(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Namespace::Bar*, std::vector<Namespace::Bar> >; _Compare = bool (*)(Namespace::Bar&, Namespace::Bar&)]’
/usr/lib/gcc/i686-pc-cygwin/4.8.3/include/c++/bits/stl_algo.h:2337:62: required from ‘void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Namespace::Bar*, std::vector<Namespace::Bar> >; _Size = int; _Compare = bool (*)(Namespace::Bar&, Namespace::Bar&)]’
/usr/lib/gcc/i686-pc-cygwin/4.8.3/include/c++/bits/stl_algo.h:5490:44: required from ‘void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = __gnu_cxx::__normal_iterator<Namespace::Bar*, std::vector<Namespace::Bar> >; _Compare = bool (*)(Namespace::Bar&, Namespace::Bar&)]’
Test007.cpp:20:61: required from here
/usr/lib/gcc/i686-pc-cygwin/4.8.3/include/c++/bits/stl_algo.h:2263:35: error: invalid initialization of reference of type ‘Namespace::Bar&’ from expression of type ‘const Namespace::Bar’
while (__comp(*__first, __pivot))
^
/usr/lib/gcc/i686-pc-cygwin/4.8.3/include/c++/bits/stl_algo.h:2266:34: error: invalid initialization of reference of type ‘Namespace::Bar&’ from expression of type ‘const Namespace::Bar’
while (__comp(__pivot, *__last))
I'd appreciate help on figuring this one out.
The std::sort reference says that the comparator function does not require const & reference arguments, but still must not modify the arguments.
It looks like your compiler is being a bit more restrictive and requiring
bool barComparator( const Bar& bar1 , const Bar& bar2 ).

compilation error ::vector ::iteratator

I encounter this error whenever I compile my prg..
c:\mingw\bin\../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_algo.h:5394:5: note: template<class _RAIter> void std::sort(_RAIter, _RAIter)
c:\mingw\bin\../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_algo.h:5430:5: note: void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = __gnu_cxx::__normal_iterator<PointTwoD*, std::vector<PointTwoD> >, _Compare = bool (MissionPlan::*)(PointTwoD&, PointTwoD&)]
c:\mingw\bin\../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_algo.h:5430:5: note: no known conversion for argument 3 from '<unresolved overloaded function type>' to 'bool (MissionPlan::*)(PointTwoD&, PointTwoD&)'
Below is actually my .cpp file..
bool MissionPlan::sortByCiv(const PointTwoD &t1, const PointTwoD &t2)
{
return t1.locationdata.getCivIndex() < t2.locationdata.getCivIndex();
}
void MissionPlan::topfives()
{
topfive.assign( point1.begin(), point1.end() );
sort(topfive.begin(), topfive.end(), sortByCiv);
for(int i=0; i < 5; i++)
{
topfive.at(i).displayPointdata();
}
}
missionplan.h
class MissionPlan
{
private:
int sizeofarray;
int sizeofarray2;
int xcordi;
int ycordi;
LocationData locationdata;
PointTwoD pointtwoD;
//MissionPlan missionplan;
public:
MissionPlan();
MissionPlan(int, int, float);
int getx();
int gety();
float civnum;
float getciv();
void stats();
void storedata(int, int, float);
void test();
void displayall();
void compute();
void topfives();
static bool sortByCiv(const PointTwoD &t1, const PointTwoD &t2);
};
My programme will compile and run smoothly when I remove this line from my code "sort(topfive.begin(), topfive.end(), sortByCiv);"
so is there a problem with that line of code or there other thing that is affecting it?
this is the error msg is get when i start compiling after I made sortByCiv statc and change the function para to a const..
In file included from c:\mingw\bin\../lib/gcc/mingw32/4.6.2/include/c++/algorithm:63:0,
from ..\src\/MissionPlan.h:9,
from ..\src\MissionPlanImp.cpp:3:
c:\mingw\bin\../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_algo.h: In function '_RandomAccessIterator std::__unguarded_partition(_RandomAccessIterator, _RandomAccessIterator, const _Tp&, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<PointTwoD*, std::vector<PointTwoD> >, _Tp = PointTwoD, _Compare = bool (*)(PointTwoD&, PointTwoD&)]':
c:\mingw\bin\../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_algo.h:2265:78: instantiated from '_RandomAccessIterator std::__unguarded_partition_pivot(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<PointTwoD*, std::vector<PointTwoD> >, _Compare = bool (*)(PointTwoD&, PointTwoD&)]'
c:\mingw\bin\../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_algo.h:2306:62: instantiated from 'void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<PointTwoD*, std::vector<PointTwoD> >, _Size = int, _Compare = bool (*)(PointTwoD&, PointTwoD&)]'
c:\mingw\bin\../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_algo.h:5445:4: instantiated from 'void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = __gnu_cxx::__normal_iterator<PointTwoD*, std::vector<PointTwoD> >, _Compare = bool (*)(PointTwoD&, PointTwoD&)]'
..\src\MissionPlanImp.cpp:140:48: instantiated from here
c:\mingw\bin\../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_algo.h:2233:4: error: invalid initialization of reference of type 'PointTwoD&' from expression of type 'const PointTwoD'
c:\mingw\bin../lib/gcc/mingw32/4.6.2/include/c++/bits/stl_algo.h:2236:4: error: invalid initialization of reference of type 'PointTwoD&' from expression of type 'const PointTwoD'
now finally the programme gets to run on command prompt but it gets terminate with the following error msg..
"terminate called after throwing an instance of 'std::out_of_range' what(): vecotr::_M_range_check"
Thanks guys I got it up and running, thanks and appreciate for all ur helps..
The issue here is that sortByCiv is a member function, which can only be invoked relative to some receiver object (i.e. myObject.sortByCiv(...) versus sortByCiv(...). The std::sort function expects you to provide as a parameter some function that can be called as a free function with two arguments that will then produce a value.
To fix this, make sortByCiv static. This makes it no longer have a receiver object and should resolve your issue.
Hope this helps!
sortByCiv is a member function and it needs special treatment; for instance, you cant cast it to function pointer type, as it has an implicit (third) this-parameter.
And in your case, you don't need to. Just move the sortByCiv(..) out of the class declaration(or make it static), as it doesn't use this parameter:
bool sortByCiv(const PointTwoD &t1, const PointTwoD &t2)
{
return t1.locationdata.getCivIndex() < t2.locationdata.getCivIndex();
}