using lower_bound or upper_bound on Structure in C++ - c++

#include <iostream>
#include <algorithm>
using namespace std;
struct arr
{
int a;int b;
}a[1000];
bool comp(arr &lhs, arr &rhs)
{ return lhs.a < rhs.a ; }
int main()
{
int n,i ;
sort(a,a+n,comp);
int ind= lower_bound(a,a+n,x,comp)-a;
return 0;
}
Error message :
/usr/include/c++/4.9/bits/predefined_ops.h: In instantiation of 'bool
__gnu_cxx::__ops::_Iter_comp_val<_Compare>::operator()(_Iterator, _Value&) [with _Iterator = arr*; _Value = const int; _Compare = bool ()(arr&, arr&)]': /usr/include/c++/4.9/bits/stl_algobase.h:965:30:
required from '_ForwardIterator std::__lower_bound(_ForwardIterator,
_ForwardIterator, const _Tp&, _Compare) [with _ForwardIterator = arr; _Tp = int; _Compare = __gnu_cxx::__ops::_Iter_comp_val]' /usr/include/c++/4.9/bits/stl_algo.h:2036:46: required from
'_FIter std::lower_bound(_FIter, _FIter, const _Tp&, _Compare) [with
_FIter = arr*; _Tp = int; _Compare = bool ()(arr&, arr&)]' prog.cpp:28:38: required from here
/usr/include/c++/4.9/bits/predefined_ops.h:141:37: error: invalid
initialization of reference of type 'arr&' from expression of type
'const int' { return bool(_M_comp(__it, __val)); }
^
I wish to use lower_bound over the struct to search for the value x that equals to a[i].a ? I have constructed the comparator function accordingly but getting a long error message of which I am not able to make anything.
What changes are required for the function to run.

lower_bound returns an iterator, not an index of the element found. You'll need to use std::distance to retrieve the index, but usually, the iterator is what you need/want for further processing.
Also note an index is usually returned as an std::size_t, not an int as you seem to assume.

As pointed in previous answers, lower_bound returns an iterator.
The type of x in lower_bound is not clear, x should also be the same type as that of the type in the container and compare function.
In this case, the type of x should be arr.

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>.

error creating a vector of structs from stl_vector.h (probably trivial)

In my code I have:
struct datapoint
{
double energy;
double probability;
};
Which is later put into a vector like so:
std::vector<datapoint> spectrum(71,0);
spectrum[0].energy = 0.937729;
spectrum[0].probability = 0.0022582628449311468;
spectrum[1].energy = 1.875458;
spectrum[1].probability = 0.0033531784328108922;
...
However, at compile time, for the line
std::vector<datapoint> spectrum(71,0);
I receive the error
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/bits/stl_vector.h: In member function âvoid std::vector<_Tp, _Alloc>::_M_initialize_dispatch(_Integer, _Integer, std::__true_type) [with _Integer = int, _Tp = datapoint, _Alloc = std::allocator<datapoint>]â:
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/bits/stl_vector.h:303: instantiated from âstd::vector<_Tp, _Alloc>::vector(_InputIterator, _InputIterator, const _Alloc&) [with _InputIterator = int, _Tp = datapoint, _Alloc = std::allocator<datapoint>]â
/src/PrimaryGeneratorAction.cc:74: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/bits/stl_vector.h:991: error: no matching function for call to âstd::vector<datapoint, std::allocator<datapoint> >::_M_fill_initialize(size_t, int&)â
I'm a bit confused as I have done this before.
You are trying to invoke the fill-constructor of vector:
explicit vector (size_type n, const value_type& val = value_type(),
const allocator_type& alloc = allocator_type());
But 0 is not a valid value of type datapoint.
struct datapoint
{
double energy;
double probability;
datapoint():energy(0.0), probability (0.0)
{}
};
then
std::vector spectrum(71);
Have fun,

Why I can't define compare without constant

If I define my compare function like this:
bool compare(Student& a, Student& b)
{
return a.n < b.n;
}
g++ will complain:
g++ -Wall main.cpp -o main
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4/algorithm:63:0,
from main.cpp:1:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4/bits/stl_algo.h: In function ‘_RandomAccessIterator std::__unguarded_partition(_RandomAccessIterator, _RandomAccessIterator, const _Tp&, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >, _Tp = Student, _Compare = bool (*)(Student&, Student&)]’:
/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4/bits/stl_algo.h:2261:78: instantiated from ‘_RandomAccessIterator std::__unguarded_partition_pivot(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >, _Compare = bool (*)(Student&, Student&)]’
/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4/bits/stl_algo.h:2302:62: instantiated from ‘void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >, _Size = long int, _Compare = bool (*)(Student&, Student&)]’
/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4/bits/stl_algo.h:5250:4: instantiated from ‘void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = __gnu_cxx::__normal_iterator<Student*, std::vector<Student> >, _Compare = bool (*)(Student&, Student&)]’
main.cpp:38:51: instantiated from here
/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4/bits/stl_algo.h:2229:4: error: invalid initialization of reference of type ‘Student&’ from expression of type ‘const Student’
/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4/bits/stl_algo.h:2232:4: error: invalid initialization of reference of type ‘Student&’ from expression of type ‘const Student’
Compilation exited abnormally with code 1 at Mon May 28 08:05:35
But if I define the compare with const type, it will compile and works fine.
And here is all the code:
class Student {
public:
Student(string);
string n;
};
bool compare(Student& a, Student& b)
{
return a.n < b.n;
}
Student::Student(string name) { n = name; }
int main()
{
Student A = Student("A");
Student B = Student("B");
vector<Student> students;
students.push_back(B);
students.push_back(A);
sort(students.begin(), students.end(), compare);
cout << "After sort" << endl;
for(vector<Student>::iterator i = students.begin(); i != students.end(); ++i) {
cout << "Student: " << i->n << endl;
}
return 0;
}
In this implementation, std::sort uses
const _Tp& std::__median(const _Tp&, const _Tp&, const _Tp&, _Compare);
In your case, _Tp is student, and _Compare is compare.
So you basically have
const Student& std::__median(const Student&, const Student&, const Student&,
bool (*)(Student&, Student&) )
or similar. Obviously, the callback can't be applied to the parameters are they are converted to const, so the failure.
Make the parameters to your compare method const.
I don't believe there is a requirement in the standard that says the parameters to the function must be const, so I believe your implementation is in error for rejecting it. However, there is a requirement that the function not modify the arguments:
From the standard -- 25.4/2
Compare is a function object type (20.8). The return value of the
function call operation applied to an object of type Compare, when
contextually converted to bool (4), yields true if the first argument
of the call is less than the second, and false otherwise. Compare comp
is used throughout for algorithms assuming an ordering relation. It is
assumed that comp will not apply any non-constant function through the
dereferenced iterator.
And the signature of std::sort from 25.4.1.1
template<class RandomAccessIterator, class Compare>
void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
So since your function is not allowed to modify its arguments, it really should be taking them in as const, but the standard does not require that. So while your implementation may be in error, I believe it is a forgivable error, as it manages to call attention to the fact that either your function is in violation of the standard by modifying its arguments, or it is not const-correct.
You should make it const since it leaves the two parameters the same.