Comparison function not working for equal_range - c++

I have the following piece of code, which saves structs into a boost::ptr_vector container. I am trying now to write a simple search function for this container via equal_range. I chose that function because I want a pointer to the element of the sequence (if it is found), or pointers to the lower and upper bound (if the element is not found):
struct COMP
{
bool operator()(const merkle_tree_node &LHS, const std::string& query){
return (LHS.word < query);
}
};
std::pair<boost::ptr_vector<merkle_tree_node>::iterator,
boost::ptr_vector<merkle_tree_node>::iterator>
search_tree(merkle_tree vWords, std::basic_string<char> query, size_t length)
{
return std::equal_range(vWords.begin(), vWords.begin()+(length-1),
query,
COMP());
}
Which I am calling via my main function as such:
std::basic_string<char> QUERY = "SOMETHING";
std::pair<boost::ptr_vector<merkle_tree_node>::iterator,
boost::ptr_vector<merkle_tree_node>::iterator> result =
search_tree(vWords, QUERY, vWords.size());
However, I am getting the following compilation error which I just can't seem to overcome:
In file included from /usr/include/c++/4.8/algorithm:62:0,
from vf-merkle.cpp:3:
/usr/include/c++/4.8/bits/stl_algo.h: In instantiation of ‘std::pair<_FIter, _FIter> std::equal_range(_FIter, _FIter, const _Tp&, _Compare) [with _FIter = boost::void_ptr_iterator<__gnu_cxx::__normal_iterator<void**, std::vector<void*, std::allocator<void*> > >, merkle_tree_node>; _Tp = std::basic_string<char>; _Compare = COMP]’:
vf-merkle.cpp:111:10: required from here
/usr/include/c++/4.8/bits/stl_algo.h:2668:36: error: no match for call to ‘(COMP) (const std::basic_string<char>&, merkle_tree_node&)’
else if (__comp(__val, *__middle))
^
vf-merkle.cpp:98:8: note: candidate is:
struct COMP
^
vf-merkle.cpp:100:7: note: bool COMP::operator()(const merkle_tree_node&, const string&)
bool operator()(const merkle_tree_node &LHS, const std::string& query){
^
vf-merkle.cpp:100:7: note: no known conversion for argument 1 from ‘const std::basic_string<char>’ to ‘const merkle_tree_node&’
Any ideas?

The short answer, is you need to provide both overloads for different orderings of the arguments
struct COMP
{
bool operator()(const merkle_tree_node &LHS, const std::string& query){
return (LHS.word < query);
}
bool operator()(const std::string& query,const merkle_tree_node &RHS){
return (query < RHS.word);
}
};
You need to do this because you are calling std::equal_range with the third argument of type string, while the iterators point to merkle_tree_node. This mixed comparison case requires you to provide additional overloads to handle the case where the string is the first argument, or when the string is the second argument. For completeness, you might want to consider adding the case where it's two instances of merkle_tree_node.

You call algorithm std:;equal_range passing to it std:;string as the third argument instead of an iterator, So your using of the algorithm is invalid. Read the description of std::equal_range before using it.

Related

Why is my variable constant when it wasn't when I defined it?

Currently, I have a problem when trying to find a variable within a vector.
I defined a vector, tests, set to contain my own structure Test. It contains two variables, one and two. Both are instances of Test.
Test isn't much, it only contains an int and char.
I defined a macro that finds wether or not an instance of an object is in a given vector or not.
When I attempt to compile my code, it results in this error:
In file included from /usr/local/Cellar/gcc/10.2.0/include/c++/10.2.0/bits/stl_algobase.h:71,
from /usr/local/Cellar/gcc/10.2.0/include/c++/10.2.0/bits/char_traits.h:39,
from /usr/local/Cellar/gcc/10.2.0/include/c++/10.2.0/ios:40,
from /usr/local/Cellar/gcc/10.2.0/include/c++/10.2.0/ostream:38,
from /usr/local/Cellar/gcc/10.2.0/include/c++/10.2.0/iostream:39,
from test.cpp:1:
/usr/local/Cellar/gcc/10.2.0/include/c++/10.2.0/bits/predefined_ops.h: In instantiation of 'bool __gnu_cxx::__ops::_Iter_equals_val<_Value>::operator()(_Iterator) [with _Iterator = __gnu_cxx::__normal_iterator<Test*, std::vector<Test> >; _Value = const Test]':
/usr/local/Cellar/gcc/10.2.0/include/c++/10.2.0/bits/stl_algobase.h:1932:14: required from '_RandomAccessIterator std::__find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<Test*, std::vector<Test> >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val<const Test>]'
/usr/local/Cellar/gcc/10.2.0/include/c++/10.2.0/bits/stl_algobase.h:1977:23: required from '_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = __gnu_cxx::__normal_iterator<Test*, std::vector<Test> >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val<const Test>]'
/usr/local/Cellar/gcc/10.2.0/include/c++/10.2.0/bits/stl_algo.h:3902:28: required from '_IIter std::find(_IIter, _IIter, const _Tp&) [with _IIter = __gnu_cxx::__normal_iterator<Test*, std::vector<Test> >; _Tp = Test]'
test.cpp:19:6: required from here
/usr/local/Cellar/gcc/10.2.0/include/c++/10.2.0/bits/predefined_ops.h:268:17: error: no match for 'operator==' (operand types are 'Test' and 'const Test')
268 | { return *__it == _M_value; }
|
What I find interesting is that the variable I am checking is considered constant, even though when I defined it, it wasn't.
Source code:
#include <iostream>
#include <vector>
#include <algorithm>
#define isin(one, two) (std::find(one.begin(), one.end(), two) != one.end())
struct Test {
int one;
char two;
};
int main() {
Test one = { 6, 'n' };
Test two = { 9, 'r' };
std::vector<Test> tests = { one, two };
if (isin(tests, one)) {
std::cout << "one is in tests\n";
} else {
std::cout << "one is not in tests\n";
}
return 0;
}
Why is one considered constant? Did I accidentally do something wrong?
error: no match for 'operator==' (operand types are 'Test' and 'const Test')
You don't have an equality operator defined for Test. You need to define operator== so it can know how to check if two instances are equal.
The error message is telling you that there is no operator== defined that can compare a non-const Test object on the left to a const Test object on the right. The compiler does not generate a default operator== for you (though, this is actually addressed in C++20, though it is not automatic, you still have to request it explicitly).
The 2nd Test in the error message is const because that is how std::find() is taking it in:
template< class InputIt, class T >
InputIt find( InputIt first, InputIt last, const T& value )
std::find() iterates the specified range comparing value to each element in the range using operator==, similar to this:
template< class InputIt, class T >
InputIt find( InputIt first, InputIt last, const T& value )
{
while (first != last) {
if (*first == value) { // <-- here
return first;
}
++first;
}
return last;
}
In this case, T is Test, so value is const Test &value. tests is a non-const std::vector<Test>, so its iterators refer to non-const Test elements. But the value being compared to them is a const Test.
You need to define an operator== for Test that can handle that comparison, eg:
struct Test {
int one;
char two;
bool operator==(const Test &rhs) const {
return one == rhs.one && two == rhs.two;
/* alternatively:
return std::tie(one, two) == std::tie(rhs.one, rhs.two);
*/
}
/* alternatively in C++20 onwards:
bool operator==(const Test &) const = default;
*/
};

Using std::stable_sort with a array of pointer to functions

I'm trying to implement a class which i can use to sort a list of files based on some different functions of sort.
I'm having trouble to use an array of pointer to function to make calls.
FileList.hpp :
class FileList
{
public:
enum sortStyle{EXTENSION, NAME, SIZE, DURATION, PATH};
//...
};
namespace SortFiles
{
struct sortFcts{
FileList::sortStyle sort;
bool (*fonc)(const FileData &, const FileData &);
};
bool sortExtension(const FileData &a, const FileData &b);
bool sortName(const FileData &a, const FileData &b);
bool sortDuration(const FileData &a, const FileData &b);
bool sortSize(const FileData &a, const FileData &b);
bool sortPath(const FileData &a, const FileData &b);
}
struct SortFiles::sortFcts tabSortFctsFileList[5] = {{FileList::EXTENSION, &SortFiles::sortExtension},
{FileList::NAME, &SortFiles::sortName},
{FileList::SIZE, &SortFiles::sortSize},
{FileList::DURATION, &SortFiles::sortDuration},
{FileList::PATH, &SortFiles::sortPath}};
FileList.cpp :
void FileList::sort(FileList::sortStyle a)
{
//std::stable_sort((this->_data).begin(), (this->_data).end(), SortFiles::sortPath);
std::stable_sort((this->_data).begin(), (this->_data).end(), tabSortFctsFileList[a]);
}
Where tabSortFctsFileList[] is just a tab of my struct where i put all my sorting methods.
My problem here is that if I use the commented way it works, but when i use the array i have a compilation error I don't know why. I know i can use a huge switch and it'll work fine but i don't want to.
Here's one of the line of the error message :
/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<FileData*, std::vector<FileData> >; _Compare = SortFiles::sortFcts]’:
/usr/include/c++/4.8/bits/stl_algo.h:3510:49:
required from ‘void std::__inplace_stable_sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<FileData*, std::vector<FileData> >; _Compare = SortFiles::sortFcts]’
/usr/include/c++/4.8/bits/stl_algo.h:5710:52:
required from ‘void std::stable_sort(_RAIter, _RAIter, _Compare) [with _RAIter = __gnu_cxx::__normal_iterator<FileData*, std::vector<FileData> >; _Compare = SortFiles::sortFcts]’
FileList.cpp:71:88: required from here
/usr/include/c++/4.8/bits/stl_algo.h:2159:29: error: no match for call to ‘(SortFiles::sortFcts) (FileData&, FileData&)’
if (__comp(*__i, *__first))
I feel like the problem here is that I shouldn't use a (*fonc) but rather a fonc as last parameter, but I already tried to do something like : (Tab[a]) but it says i have no match for operator.
What should I do to fix it ?
You are trying to pass an object of type sortFcts as the predicate parameter of std::stable_sort(). Objects are type sortFcts are not callable, though. There are two simple fixes:
The simpler [and recommended] fix is to just get the fonc member of the object:
... tabSortFctsFileList[a].fonc ...
Make objects of type sortFcts callable as a predicate by adding a suitable function call operator:
struct sortFcts {
// ...
bool operator()(const FileData &a, const FileData &b) const {
return this->fonc(a, b);
}
};

Sorting vector of Pointers of Custom Class

I have vector<FPGA*> current_generation_, which I'd like to sort by FPGA member fitness_ using the sort_members function. Applicable code follows:
bool sort_members (FPGA* fpga_first, FPGA* fpga_second) {
return (fpga_first->fitness() < fpga_second->fitness());
};
fpga.hpp
#include <vector>
class FPGA {
public:
explicit FPGA(int input_gates, int output_gates, int normal_gates);
const int fitness();
protected:
int fitness_;
};
fpga.cpp
FPGA::FPGA() {
this->fitness_ = 0;
}
const int FPGA::fitness() {
return this->fitness_;
}
implementation:
std::sort(this->current_generation_.begin(), this->current_generation_.end(), sort_members);
errors:
/usr/include/c++/4.9/bits/stl_algo.h: In instantiation of ‘void std::__sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = std::__detail::_Node_iterator<std::pair<const int, FPGA*>, false, false>; _Compare = __gnu_cxx::__ops::_Iter_comp_iter<bool (*)(FPGA*, FPGA*)>]’:
/usr/include/c++/4.9/bits/stl_algo.h:4717:78: required from ‘void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = std::__detail::_Node_iterator<std::pair<const int, FPGA*>, false, false>; _Compare = bool (*)(FPGA*, FPGA*)]’
/usr/include/c++/4.9/bits/stl_algo.h:1968:22: error: no match for ‘operator-’ (operand types are ‘std::__detail::_Node_iterator<std::pair<const int, FPGA*>, false, false>’ and ‘std::__detail::_Node_iterator<std::pair<const int, FPGA*>, false, false>’)
std::__lg(__last - __first) * 2,
The remainder of the total error string is huge, but I believe is mostly what the compiler believes(falsely) are candidates. I'm not extremely familiar with c++, and a compiler error of this magnitude and complexity is confusing to me.
I can provide more context if needed. Thanks!
EDIT: A dash.
EDIT EDIT: I screwed up, and was trying to sort the wrong member. Hooray.
The only error that I see is this>current_generation_.end() instead that ->.
In addition you should consider declaring your compare fuction as accepting two const FPGA* instead that just FPGA*. This will force you to declare fitness() as const int fitness() const but it makes sense to have it const.
Mind that since you are using C++11 you can directly use a lambda:
std::sort(data.begin(), data.end(), [](const FPGA* f1, const FPGA* f2) { ... });
You also have the choice to overload operator< directly:
class FPGA {
...
bool operator<(const FPGA* other) const { return fitness_ < other->fitness_; }
}
std::sort(data.begin(), data.end());
This could be useful if it doesn't make sense to have other criteria to compare two FPGA instances since you add some semantics to the object itself.

How to sort a std::set with const getters

I have a std::set container whose elements are objects of the following class:
class LaneConnector {
public:
const Lane* getLaneFrom() const {
return From;
}
const Lane* getLaneTo() const {
return To;
}
private:
Lane* From;
Lane* To;
}
and my comparator function is as follows:
struct MyLaneConectorSorter {
bool operator() (LaneConnector * c, LaneConnector * d)
{
Lane* a = const_cast<Lane*>(c->getLaneFrom());
Lane* b = const_cast<Lane*>(d->getLaneFrom());
return (a->getLaneID() < b->getLaneID());
}
} myLaneConnectorSorter;
Now when I try to sort the elements in the set with:
//dont panic, the container just came through a const_iterator of a std::map :)
const std::set<LaneConnector*> & tempLC = (*it_cnn).second;
std::sort(tempLC.begin(), tempLC.end(), myLaneConnectorSorter);
I get a frenzy of errors starting with the following lines, Appreciate if you help me solve this problem.
Thanks:
/usr/include/c++/4.6/bits/stl_algo.h: In function ‘void std::sort(_RAIter, _RAIter, _Compare) [with _RAIter = std::_Rb_tree_const_iterator<LaneConnector*>, _Compare = {anonymous}::MyLaneConectorSorter]’:
/home/.../dev/Basic/shared/conf/simpleconf.cpp:1104:65: instantiated from here
/usr/include/c++/4.6/bits/stl_algo.h:5368:4: error: no match for ‘operator-’ in ‘__last - __first’
/usr/include/c++/4.6/bits/stl_algo.h:5368:4: note: candidates are:
/usr/include/c++/4.6/bits/stl_iterator.h:321:5: note: template<class _Iterator> typename std::reverse_iterator::difference_type std::operator-(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_Iterator>&)
/usr/include/c++/4.6/bits/stl_iterator.h:378:5: note: template<class _IteratorL, class _IteratorR> typename std::reverse_iterator<_IteratorL>::difference_type std::operator-(const std::reverse_iterator<_IteratorL>&, const std::reverse_iterator<_IteratorR>&)
/usr/include/c++/4.6/bits/stl_bvector.h:181:3: note: std::ptrdiff_t std::operator-(const std::_Bit_iterator_base&, const std::_Bit_iterator_base&)
/usr/include/c++/4.6/bits/stl_bvector.h:181:3: note: no known conversion for argument 1 from ‘std::_Rb_tree_const_iterator<LaneConnector*>’ to ‘const std::_Bit_iterator_base&’
First, you cannot sort an std::set. It is a sorted structure, sorting happens upon construction or insertion.
Second, you can construct an std::set with your own sorting functor, and you can avoid unnecessary const_casts by making it take const pointers:
struct MyLaneConectorSorter {
bool operator() (const LaneConnector* lhs, const LaneConnector* rhs) const
{
// you may want to put some null pointer checks in here
const Lane* a = lhs->getLaneFrom();
const Lane* b = rhs->getLaneFrom();
return a->getLaneID() < b->getLaneID();
}
};
and instantiate the set like this:
std::set<LaneConnector*, MyLaneConectorSorter> s(MyLaneConectorSorter());
or, if you want to construct it from a different set, with a different ordering,
std::set<LaneConnector*> orig = ..... ;
....
std::set<LaneConnector*, MyLaneConectorSorter> s(orig.begin(), orig.end(), MyLaneConectorSorter());

C++ - Using std::count() with abstract data types?

My code is using std::count() on a list of an abstract data type that i have defined. (Sommet or Edge in english). But it doesn't work, although i've overloaded the < and == operators like this :
bool operator< (const Sommet &left, const Sommet &right)
{
if(left.m_id_sommet < right.m_id_sommet)
return true;
return false;
}
bool operator== (const Sommet &left, const Sommet &right)
{
if(left.m_id_sommet == right.m_id_sommet)
return true;
return false;
}
Just notice that this worked using std::sort() and std::unique().
The errors are:
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h: In function 'typename std::iterator_traits<_Iterator>::difference_type std::count(_InputIterator, _InputIterator, const _Tp&) [with _InputIterator = __gnu_cxx::__normal_iterator<Sommet*, std::vector<Sommet, std::allocator<Sommet> > >, _Tp = __gnu_cxx::__normal_iterator<Sommet*, std::vector<Sommet, std::allocator<Sommet> > >]':
Graphe.cpp:43: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:422: error: no match for 'operator==' in '__first.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = Sommet*, _Container = std::vector<Sommet, std::allocator<Sommet> >]() == __value'
Sommet.h:7: note: candidates are: bool operator==(const Sommet&, const Sommet&)
Thanks !
EDIT
This is how i used std::count() :
for(vector<Sommet>::iterator iter = m_sommets.begin();
iter != s_iter_end; iter++)
{
iter->SetNbSuccesseurs(count(m_sommets.begin(), m_sommets.end(), iter));
}
It looks like you are passing in an iterator as the last parameter to std::count whereas you need to pass in a value (by const reference).
Post edit: it looks like I was correct, you are passing iter which is an iterator. You need to dereference it first. Try passing *iter instead.
What you need to pass to count is a value, not an iterator:
iter->SetNbSuccesseurs(count(m_sommets.begin(), m_sommets.end(), *iter));