How to solve ambiguity in operator overloading embedded inside a struct? - c++

In the following code, the g++ compiler surprisingly cannot decide which operator to use when they are embedded in a struct to serve as a comparator argument in a set:
#include <string>
#include <set>
struct KeyWord {
std::string str;
int qt;
KeyWord(const std::string aKw = "", const int aQt = 0) : str(aKw), qt(aQt) {}
};
struct CompareKeywords {
bool operator() (const std::string& left, const std::string& right) const {
if (left.size() > right.size()) return true;
else if (left.size() < right.size()) return false;
else return (left < right);
}
bool operator() (const KeyWord& left, const KeyWord& right) {
if (left.str.size() > right.str.size()) return true;
else if (left.str.size() < right.str.size()) return false;
else return (left.str < right.str);
}
};
int main() {
std::set<std::string, CompareKeywords> a;
std::set<KeyWord, CompareKeywords> b;
std::string s("_s_");
KeyWord k("_k_", 1);
a.insert(s);
b.insert(k);
}
Here is the compiler output:
g++ oa.cpp
/usr/include/c++/4.9/bits/stl_tree.h: In instantiation of ‘std::pair<std::_Rb_tree_node_base*, std::_Rb_tree_node_base*> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_get_insert_unique_pos(const key_type&) [with _Key = std::basic_string<char>; _Val = std::basic_string<char>; _KeyOfValue = std::_Identity<std::basic_string<char> >; _Compare = CompareKeywords; _Alloc = std::allocator<std::basic_string<char> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::key_type = std::basic_string<char>]’:
/usr/include/c++/4.9/bits/stl_tree.h:1498:47: required from ‘std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = std::basic_string<char>; _Val = std::basic_string<char>; _KeyOfValue = std::_Identity<std::basic_string<char> >; _Compare = CompareKeywords; _Alloc = std::allocator<std::basic_string<char> >]’
/usr/include/c++/4.9/bits/stl_set.h:502:29: required from ‘std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const value_type&) [with _Key = std::basic_string<char>; _Compare = CompareKeywords; _Alloc = std::allocator<std::basic_string<char> >; typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator = std::_Rb_tree_const_iterator<std::basic_string<char> >; std::set<_Key, _Compare, _Alloc>::value_type = std::basic_string<char>]’
oa.cpp:28:13: required from here
oa.cpp:11:8: note: candidate 1: bool CompareKeywords::operator()(const string&, const string&) const
bool operator() (const std::string& left, const std::string& right) const {
^
oa.cpp:16:8: note: candidate 2: bool CompareKeywords::operator()(const KeyWord&, const KeyWord&)
bool operator() (const KeyWord& left, const KeyWord& right) {
^
oa.cpp:11:8: note: candidate 1: bool CompareKeywords::operator()(const string&, const string&) const
bool operator() (const std::string& left, const std::string& right) const {
^
oa.cpp:16:8: note: candidate 2: bool CompareKeywords::operator()(const KeyWord&, const KeyWord&)
bool operator() (const KeyWord& left, const KeyWord& right) {
^
/usr/include/c++/4.9/bits/stl_tree.h: In instantiation of ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr, std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr, const _Val&) [with _Key = std::basic_string<char>; _Val = std::basic_string<char>; _KeyOfValue = std::_Identity<std::basic_string<char> >; _Compare = CompareKeywords; _Alloc = std::allocator<std::basic_string<char> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::basic_string<char> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr = std::_Rb_tree_node_base*]’:
/usr/include/c++/4.9/bits/stl_tree.h:1502:38: required from ‘std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = std::basic_string<char>; _Val = std::basic_string<char>; _KeyOfValue = std::_Identity<std::basic_string<char> >; _Compare = CompareKeywords; _Alloc = std::allocator<std::basic_string<char> >]’
/usr/include/c++/4.9/bits/stl_set.h:502:29: required from ‘std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const value_type&) [with _Key = std::basic_string<char>; _Compare = CompareKeywords; _Alloc = std::allocator<std::basic_string<char> >; typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator = std::_Rb_tree_const_iterator<std::basic_string<char> >; std::set<_Key, _Compare, _Alloc>::value_type = std::basic_string<char>]’
oa.cpp:28:13: required from here
oa.cpp:11:8: note: candidate 1: bool CompareKeywords::operator()(const string&, const string&) const
bool operator() (const std::string& left, const std::string& right) const {
^
oa.cpp:16:8: note: candidate 2: bool CompareKeywords::operator()(const KeyWord&, const KeyWord&)
bool operator() (const KeyWord& left, const KeyWord& right) {
^
The last lines show the ambiguity where the compiler shows two candidates.
Why this ambiguity exist? How should I supress it?

It looks like some builds of gcc have this peculiar feature of printing these messages out of the blue. For example all builds on coliru do this.
These messages are not errors because the object file is produced, and they are not warnings because -Werror doesn't turn them into errors. They look rather like a compiler bug. Obviously one cannot suppress these non-warnings with compiler flags.
Same exact versions of gcc on my machine don't print any messages with this code. They do print regular (tagged with the coloured "warning", non-suppressible, but turnable-to-error) warnings with similar code.
On coliru, making the second operator() const suppresses the messages.

Two separate struct with only one operator in each of them dedicated to a type solves the problem:
#include <string>
#include <set>
struct KeyWord {
std::string str;
int qt;
KeyWord(const std::string aKw = "", const int aQt = 0) : str(aKw), qt(aQt) {}
};
struct CompareStrings {
bool operator() (const std::string& left, const std::string& right) const {
if (left.size() > right.size()) return true;
else if (left.size() < right.size()) return false;
else return (left < right);
}
};
struct CompareKeywords {
bool operator() (const KeyWord& left, const KeyWord& right) {
if (left.str.size() > right.str.size()) return true;
else if (left.str.size() < right.str.size()) return false;
else return (left.str < right.str);
}
};
int main() {
std::set<std::string, CompareStrings> a;
std::set<KeyWord, CompareKeywords> b;
std::string s("_s_");
KeyWord k("_k_", 1);
a.insert(s);
b.insert(k);
}

There was an error in the initial code:
bool operator() (const std::string& left, const std::string& right) const {
bool operator() (const KeyWord& left, const KeyWord& right) {
Suppressing the const at the end of the first declaration, or adding one to the second one solves the problem. But still, I don't understand why the compiler was confused.
So, either:
bool operator() (const std::string& left, const std::string& right) {
bool operator() (const KeyWord& left, const KeyWord& right) {
or:
bool operator() (const std::string& left, const std::string& right) const {
bool operator() (const KeyWord& left, const KeyWord& right) const {
works.
Note: Wheither a const function or not is discussed here.
Since I want overloading, both functions are expected to have the same behaviour, so const to both or none. If I would have liked different behaviours with one with const and the other without (in the case I would have had some struct members I would have wanted to modify), the second solution below with separate struct for each operator definition would be the solution.

Related

Static assertion failed error in defining set (STL container) with user defined objects c++17

I defined a set with data type as user defined object here.
#include<bits/stdc++.h>
using namespace std;
class triplets{
public:
int x,y,z;
triplets(){
}
triplets(int x,int y,int z){
this->x=x;
this->y=y;
this->z=z;
}
};
class Cmp{
public:
Cmp(){};
bool operator() (const triplets &a, const triplets &b){
if( a.x == b.x){
return a.y < b.y;
}else{
return a.x < b.x;
}
}
};
int main(){
set<triplets,Cmp>s;
s.insert(triplets(2,4,5));
return 0;
}
The code compiles fine in c++11 and c++14 versions. But it doesn't compile in c++17 and above. It throws following error.
In file included from /usr/include/c++/11/map:60,
from /usr/include/x86_64-linux-gnu/c++/11/bits/stdc++.h:81,
from Arrays/TwoPointer/test.cpp:1:
/usr/include/c++/11/bits/stl_tree.h: In instantiation of ‘static const _Key& std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_S_key(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Const_Link_type) [with _Key = triplets; _Val = triplets; _KeyOfValue = std::_Identity<triplets>; _Compare = Cmp; _Alloc = std::allocator<triplets>; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Const_Link_type = const std::_Rb_tree_node<triplets>*]’:
/usr/include/c++/11/bits/stl_tree.h:2071:47: required from ‘std::pair<std::_Rb_tree_node_base*, std::_Rb_tree_node_base*> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_get_insert_unique_pos(const key_type&) [with _Key = triplets; _Val = triplets; _KeyOfValue = std::_Identity<triplets>; _Compare = Cmp; _Alloc = std::allocator<triplets>; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::key_type = triplets]’
/usr/include/c++/11/bits/stl_tree.h:2124:4: required from ‘std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(_Arg&&) [with _Arg = triplets; _Key = triplets; _Val = triplets; _KeyOfValue = std::_Identity<triplets>; _Compare = Cmp; _Alloc = std::allocator<triplets>]’
/usr/include/c++/11/bits/stl_set.h:521:25: required from ‘std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Tp>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(std::set<_Key, _Compare, _Alloc>::value_type&&) [with _Key = triplets; _Compare = Cmp; _Alloc = std::allocator<triplets>; typename std::_Rb_tree<_Key, _Key, std::_Identity<_Tp>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator = std::_Rb_tree<triplets, triplets, std::_Identity<triplets>, Cmp, std::allocator<triplets> >::const_iterator; typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other = std::allocator<triplets>; typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key> = __gnu_cxx::__alloc_traits<std::allocator<triplets>, triplets>::rebind<triplets>; typename _Alloc::value_type = triplets; std::set<_Key, _Compare, _Alloc>::value_type = triplets]’
Arrays/TwoPointer/test.cpp:29:13: required from here
/usr/include/c++/11/bits/stl_tree.h:770:15: error: static assertion failed: comparison object must be invocable as const
770 | is_invocable_v<const _Compare&, const _Key&, const _Key&>,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/11/bits/stl_tree.h:770:15: note: ‘std::is_invocable_v<const Cmp&, const triplets&, const triplets&>’ evaluates to false
Any idea how should I define the set?
bool operator() (const triplets &a, const triplets &b){
should be
bool operator() (const triplets &a, const triplets &b) const{

Error using custom comparator for sorting map

I'm trying to sort the keys of a Sparse Matrix by row and column, and I want to use a map for this purpose. I added a custom comparator to ensure that, but I facing the following compilation error:
g++ -O2 -Wall -std=c++11 -Wextra -Wpedantic -c -o main.o main.cpp
In file included from /usr/include/c++/9/map:60,
from Matrix.hh:1,
from main.cpp:3:
/usr/include/c++/9/bits/stl_tree.h: In instantiation of ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::find(const _Key&) const [with _Key = std::pair<int, int>; _Val = std::pair<const std::pair<int, int>, int>; _KeyOfValue = std::_Select1st<std::pair<const std::pair<int, int>, int> >; _Compare = compare_keys; _Alloc = std::allocator<std::pair<const std::pair<int, int>, int> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator = std::_Rb_tree_const_iterator<std::pair<const std::pair<int, int>, int> >]’:
/usr/include/c++/9/bits/stl_map.h:1215:31: required from ‘std::map<_Key, _Tp, _Compare, _Alloc>::size_type std::map<_Key, _Tp, _Compare, _Alloc>::count(const key_type&) const [with _Key = std::pair<int, int>; _Tp = int; _Compare = compare_keys; _Alloc = std::allocator<std::pair<const std::pair<int, int>, int> >; std::map<_Key, _Tp, _Compare, _Alloc>::size_type = long unsigned int; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = std::pair<int, int>]’
Matrix.hh:23:9: required from ‘bool Matrix<T>::emplace(int, int, T) [with T = int]’
main.cpp:7:5: required from here
/usr/include/c++/9/bits/stl_tree.h:2572:8: error: no match for call to ‘(const compare_keys) (const std::pair<int, int>&, const std::pair<int, int>&)’
2571 | return (__j == end()
| ~~~~~~~~~~~~~
2572 | || _M_impl._M_key_compare(__k,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2573 | _S_key(__j._M_node))) ? end() : __j;
| ~~~~~~~~~~~~~~~~~~~~~
In file included from main.cpp:3:
Matrix.hh:6:10: note: candidate: ‘bool compare_keys::operator()(const key&, const key&)’ <near match>
6 | bool operator() (const key& left_key, const key& right_key) {
| ^~~~~~~~
Matrix.hh:6:10: note: passing ‘const compare_keys*’ as ‘this’ argument discards qualifiers
In file included from /usr/include/c++/9/map:60,
from Matrix.hh:1,
from main.cpp:3:
/usr/include/c++/9/bits/stl_tree.h: In instantiation of ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_lower_bound(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Const_Link_type, std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Const_Base_ptr, const _Key&) const [with _Key = std::pair<int, int>; _Val = std::pair<const std::pair<int, int>, int>; _KeyOfValue = std::_Select1st<std::pair<const std::pair<int, int>, int> >; _Compare = compare_keys; _Alloc = std::allocator<std::pair<const std::pair<int, int>, int> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator = std::_Rb_tree_const_iterator<std::pair<const std::pair<int, int>, int> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Const_Link_type = const std::_Rb_tree_node<std::pair<const std::pair<int, int>, int> >*; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Const_Base_ptr = const std::_Rb_tree_node_base*]’:
/usr/include/c++/9/bits/stl_tree.h:2570:22: required from ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::find(const _Key&) const [with _Key = std::pair<int, int>; _Val = std::pair<const std::pair<int, int>, int>; _KeyOfValue = std::_Select1st<std::pair<const std::pair<int, int>, int> >; _Compare = compare_keys; _Alloc = std::allocator<std::pair<const std::pair<int, int>, int> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator = std::_Rb_tree_const_iterator<std::pair<const std::pair<int, int>, int> >]’
/usr/include/c++/9/bits/stl_map.h:1215:31: required from ‘std::map<_Key, _Tp, _Compare, _Alloc>::size_type std::map<_Key, _Tp, _Compare, _Alloc>::count(const key_type&) const [with _Key = std::pair<int, int>; _Tp = int; _Compare = compare_keys; _Alloc = std::allocator<std::pair<const std::pair<int, int>, int> >; std::map<_Key, _Tp, _Compare, _Alloc>::size_type = long unsigned int; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = std::pair<int, int>]’
Matrix.hh:23:9: required from ‘bool Matrix<T>::emplace(int, int, T) [with T = int]’
main.cpp:7:5: required from here
/usr/include/c++/9/bits/stl_tree.h:1945:6: error: no match for call to ‘(const compare_keys) (const std::pair<int, int>&, const std::pair<int, int>&)’
1945 | if (!_M_impl._M_key_compare(_S_key(__x), __k))
In file included from main.cpp:3:
Matrix.hh:6:10: note: candidate: ‘bool compare_keys::operator()(const key&, const key&)’ <near match>
6 | bool operator() (const key& left_key, const key& right_key) {
| ^~~~~~~~
Matrix.hh:6:10: note: passing ‘const compare_keys*’ as ‘this’ argument discards qualifiers
The Matrix class:
#include <map>
#include <iostream>
typedef std::pair<int,int> key;
struct compare_keys {
bool operator() (const key& left_key, const key& right_key) {
if (left_key.first < right_key.first) return true;
if (left_key.first > right_key.first) return false;
return left_key.second > right_key.second;
}
};
template <typename T>
class Matrix {
private:
//Sparse matrix representation
std::map<key, T, compare_keys> values;
int max_row, max_col;
public:
Matrix() : max_row(0), max_col(0) {};
Matrix(int rows, int cols) : max_row(rows), max_col(cols) {};
bool emplace(int row, int col, T value) {
if (this->values.count(std::make_pair(row, col)))
return false;
this->values[std::make_pair(row, col)] = value;
if (row > max_row) max_row = row;
if (col > max_col) max_col = col;
return true;
}
};
I don't see why the compare_keys operator doesn't match the comparator in the map constructor.
You are missing const.
bool operator() (const key& left_key, const key& right_key) const {
^^^^^

required from 'std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique

I'm getting a compilation error,
required from 'std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(_Arg&&) [with _Arg = Solution::EnhancedNode* const&; _Key = Solution::EnhancedNode*; _Val = Solution::EnhancedNode*; _KeyOfValue = std::_Identity<Solution::EnhancedNode*>; _Compare = Solution::EnhancedNodeComparator; _Alloc = std::allocator<Solution::EnhancedNode*>]'
Unfortunately there is no line number, but my removing sections of code, I believe it has something to do with an std::set that I want to apply a custom comparator to:
class EnhancedNode {
public:
EnhancedNode(TreeNode* node) {
node_ = node;
distance_ = numeric_limits<double>::max();
discarded_ = false;
}
TreeNode* node_;
double distance_;
bool discarded_;
};
struct EnhancedNodeComparator {
bool operator() (const EnhancedNode*& a, const EnhancedNode*& b) const {
return a->distance_ < b->distance_;
}
};
set<EnhancedNode*, EnhancedNodeComparator> closest_;
set<EnhancedNode*, EnhancedNodeComparator> next_;
Am I doing anything obviously wrong?
The comparator of std::set should definitely accept references to the const qualified type which is in the set.
What you got wrong is the qualification of the type in the set. It's EnhancedNode*, so qualifying it with const should give EnhancedNode* const. And not const EnhancedNode*.
This is once again a case of leading const being misleading. Change your original comparator, with reference and all, to this:
struct EnhancedNodeComparator {
bool operator() (EnhancedNode const * const& a, EnhancedNode const * const& b) const {
return a->distance_ < b->distance_;
}
};
You can keep the const-qualified pointee, as well. Since C++ explicitly allows it.
The reason that your issue was fixed when you got rid of the reference, is that top-level const is ignored when passing by value. So it didn't matter the the pointer your function received as an argument wasn't const qualified. It was just a copy of the original.
While creating a Minimal, Complete, VerifiableTM example, I was able to solve my problem. I'm posting it anyway because Google surprisingly had zero hits for the first portions of my error in quotes.
Turns out I didn't need the &s in
struct EnhancedNodeComparator {
bool operator() (const EnhancedNode*& a, const EnhancedNode*& b) const {
I found this out by compiling on a different compiler, http://cpp.sh,
#include <limits>
#include <set>
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class EnhancedNode {
public:
EnhancedNode(TreeNode* node) {
node_ = node;
distance_ = numeric_limits<double>::max();
discarded_ = false;
}
TreeNode* node_;
double distance_;
bool discarded_;
};
struct EnhancedNodeComparator {
bool operator() (const EnhancedNode*& a, const EnhancedNode*& b) const {
return a->distance_ < b->distance_;
}
};
int main()
{
set<EnhancedNode*, EnhancedNodeComparator> closest_;
closest_.insert(new EnhancedNode(new TreeNode(1)));
return 0;
}
and getting a more helpful error:
In file included from /usr/include/c++/4.9/set:60:0,
from 3:
/usr/include/c++/4.9/bits/stl_tree.h: In instantiation of 'std::pair<std::_Rb_tree_node_base*, std::_Rb_tree_node_base*> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_get_insert_unique_pos(const key_type&) [with _Key = EnhancedNode*; _Val = EnhancedNode*; _KeyOfValue = std::_Identity<EnhancedNode*>; _Compare = EnhancedNodeComparator; _Alloc = std::allocator<EnhancedNode*>; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::key_type = EnhancedNode*]':
/usr/include/c++/4.9/bits/stl_tree.h:1498:47: required from 'std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(_Arg&&) [with _Arg = EnhancedNode*; _Key = EnhancedNode*; _Val = EnhancedNode*; _KeyOfValue = std::_Identity<EnhancedNode*>; _Compare = EnhancedNodeComparator; _Alloc = std::allocator<EnhancedNode*>]'
/usr/include/c++/4.9/bits/stl_set.h:511:40: required from 'std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(std::set<_Key, _Compare, _Alloc>::value_type&&) [with _Key = EnhancedNode*; _Compare = EnhancedNodeComparator; _Alloc = std::allocator<EnhancedNode*>; typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator = std::_Rb_tree_const_iterator<EnhancedNode*>; std::set<_Key, _Compare, _Alloc>::value_type = EnhancedNode*]'
33:54: required from here
/usr/include/c++/4.9/bits/stl_tree.h:1445:11: error: no match for call to '(EnhancedNodeComparator) (EnhancedNode* const&, EnhancedNode* const&)'
__comp = _M_impl._M_key_compare(__k, _S_key(__x));
^
24:8: note: candidate is:
25:10: note: bool EnhancedNodeComparator::operator()(const EnhancedNode*&, const EnhancedNode*&) const
25:10: note: no known conversion for argument 1 from 'const key_type {aka EnhancedNode* const}' to 'const EnhancedNode*&'
In file included from /usr/include/c++/4.9/set:60:0,
from 3:
/usr/include/c++/4.9/bits/stl_tree.h:1456:7: error: no match for call to '(EnhancedNodeComparator) (EnhancedNode* const&, EnhancedNode* const&)'
if (_M_impl._M_key_compare(_S_key(__j._M_node), __k))
^
24:8: note: candidate is:
25:10: note: bool EnhancedNodeComparator::operator()(const EnhancedNode*&, const EnhancedNode*&) const
25:10: note: no known conversion for argument 1 from 'EnhancedNode* const' to 'const EnhancedNode*&'
In file included from /usr/include/c++/4.9/set:60:0,
from 3:
/usr/include/c++/4.9/bits/stl_tree.h: In instantiation of 'std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr, std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr, _Arg&&) [with _Arg = EnhancedNode*; _Key = EnhancedNode*; _Val = EnhancedNode*; _KeyOfValue = std::_Identity<EnhancedNode*>; _Compare = EnhancedNodeComparator; _Alloc = std::allocator<EnhancedNode*>; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<EnhancedNode*>; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr = std::_Rb_tree_node_base*]':
/usr/include/c++/4.9/bits/stl_tree.h:1502:38: required from 'std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(_Arg&&) [with _Arg = EnhancedNode*; _Key = EnhancedNode*; _Val = EnhancedNode*; _KeyOfValue = std::_Identity<EnhancedNode*>; _Compare = EnhancedNodeComparator; _Alloc = std::allocator<EnhancedNode*>]'
/usr/include/c++/4.9/bits/stl_set.h:511:40: required from 'std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(std::set<_Key, _Compare, _Alloc>::value_type&&) [with _Key = EnhancedNode*; _Compare = EnhancedNodeComparator; _Alloc = std::allocator<EnhancedNode*>; typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, typename __gnu_cxx::__alloc_traits<_Alloc>::rebind<_Key>::other>::const_iterator = std::_Rb_tree_const_iterator<EnhancedNode*>; std::set<_Key, _Compare, _Alloc>::value_type = EnhancedNode*]'
33:54: required from here
/usr/include/c++/4.9/bits/stl_tree.h:1140:8: error: no match for call to '(EnhancedNodeComparator) (EnhancedNode*&, EnhancedNode* const&)'
|| _M_impl._M_key_compare(_KeyOfValue()(__v),
^
24:8: note: candidate is:
25:10: note: bool EnhancedNodeComparator::operator()(const EnhancedNode*&, const EnhancedNode*&) const
25:10: note: no known conversion for argument 1 from 'EnhancedNode*' to 'const EnhancedNode*&'
I don't really understand why this is so. All the examples for custom comparators for std::set I found online seemed to add &. If someone could explain as an answer, I would select it as the complete answer.

Trouble with operator < overloading in C++

I'm just learning operator overloading and am trying to add two vertices of my custom class to a set. This causes strange errors and my attempt at < overloading didn't work.
Can someone explain what's wrong?
My Vertex class:
class Vertex{
public:
int i, j;
set<Vertex> adj; //adjacent vertices
Vertex(){
i = j = -1;
}
~Vertex(){
adj.clear();
}
//end constructors and destructors
void setPos(int row, int col){
i = row;
j = col;
}//end setPos()
/** must overload for set<Vertex> to function */
bool operator < (const Vertex &o){
if(i < o.i)
return true;
if(i > o.i)
return false;
return j < o.j;
}
};//END class Vertex
But calling this function in main causes strange output in terminal and an error:
/** connect v1 and v2 such that they are adjacent */
void addEdge(Vertex v1, Vertex v2){
v1.adj.insert(v2);
v2.adj.insert(v1);
}//END addEdge()
Error:
In file included from c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\string:48:0,
from c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\locale_cla
sses.h:40,
from c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\ios_base.h
:41,
from c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\ios:42,
from c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\ostream:38,
from c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\iostream:39,
from FileMaze.cc:2:
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_function.h: In instantiation
of 'bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = V
ertex]':
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_tree.h:1321:11: required f
rom 'std::pair<std::_Rb_tree_node_base*, std::_Rb_tree_node_base*> std::_Rb_tree
<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_get_insert_unique_pos(const key_
type&) [with _Key = Vertex; _Val = Vertex; _KeyOfValue = std::_Identity<Vertex>;
_Compare = std::less<Vertex>; _Alloc = std::allocator<Vertex>; std::_Rb_tree<_K
ey, _Val, _KeyOfValue, _Compare, _Alloc>::key_type = Vertex]'
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_tree.h:1374:47: required f
rom 'std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _Ke
yOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = Vertex;
_Val = Vertex; _KeyOfValue = std::_Identity<Vertex>; _Compare = std::less<Vertex
>; _Alloc = std::allocator<Vertex>]'
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_set.h:463:29: required fro
m 'std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare,
typename _Alloc::rebind<_Key>::other>::const_iterator, bool> std::set<_Key, _Com
pare, _Alloc>::insert(const value_type&) [with _Key = Vertex; _Compare = std::le
ss<Vertex>; _Alloc = std::allocator<Vertex>; typename std::_Rb_tree<_Key, _Key,
std::_Identity<_Key>, _Compare, typename _Alloc::rebind<_Key>::other>::const_ite
rator = std::_Rb_tree_const_iterator<Vertex>; std::set<_Key, _Compare, _Alloc>::
value_type = Vertex]'
FileMaze.cc:47:18: required from here
c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_function.h:235:20: error: pa
ssing 'const Vertex' as 'this' argument of 'bool Vertex::operator<(const Vertex&
)' discards qualifiers [-fpermissive]
{ return __x < __y; }
^
make: *** [FileMaze.o] Error 1
The operator< function needs to be a const member function. Change it to
bool operator < (const Vertex &o) const;
I recommend you to check this page of c++ FAQ.
In fact when you overload functions like Less operator, you don't change the objects and so It is expected that to be overloaded as const member function :
bool operator < (const Vertex &o) const {
^~~~~
}

Problem with std::map and std::pair

I have a small program I want to execute to test something
#include <map>
#include <iostream>
using namespace std;
struct _pos{
float xi;
float xf;
bool operator<(_pos& other){
return this->xi < other.xi;
}
};
struct _val{
float f;
};
int main()
{
map<_pos,_val> m;
struct _pos k1 = {0,10};
struct _pos k2 = {10,15};
struct _val v1 = {5.5};
struct _val v2 = {12.3};
m.insert(std::pair<_pos,_val>(k1,v1));
m.insert(std::pair<_pos,_val>(k2,v2));
return 0;
}
The problem is that when I try to compile it, I get the following error
$ g++ m2.cpp -o mtest
In file included from /usr/include/c++/4.4/bits/stl_tree.h:64,
from /usr/include/c++/4.4/map:60,
from m2.cpp:1:
/usr/include/c++/4.4/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = _pos]’:
/usr/include/c++/4.4/bits/stl_tree.h:1170: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = _pos, _Val = std::pair<const _pos, _val>, _KeyOfValue = std::_Select1st<std::pair<const _pos, _val> >, _Compare = std::less<_pos>, _Alloc = std::allocator<std::pair<const _pos, _val> >]’
/usr/include/c++/4.4/bits/stl_map.h:500: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::insert(const std::pair<const _Key, _Tp>&) [with _Key = _pos, _Tp = _val, _Compare = std::less<_pos>, _Alloc = std::allocator<std::pair<const _pos, _val> >]’
m2.cpp:30: instantiated from here
/usr/include/c++/4.4/bits/stl_function.h:230: error: no match for ‘operator<’ in ‘__x < __y’
m2.cpp:9: note: candidates are: bool _pos::operator<(_pos&)
$
I thought that declaring the operator< on the key would solve the problem, but its still there.
What could be wrong?
Thanks in advance.
The problem is this:
bool operator<(_pos& other)
Should be this:
bool operator<(const _pos& other) const {
// ^^^^ ^^^^^
Without the first const, the right-hand side of the comparison (b in a < b) cannot be const, since without const the function may modify its argument.
Without the second const, the left-hand side of the comparison (a in a < b) cannot be const, since without const the function may modify this.
Internally, the key's of a map are always const.
It should be noted that you should prefer to use nonmember functions. That is, better is a free-function:
bool operator<(const _pos& lhs, const _pos& rhs)
{
return lhs.xi < rhs.xi;
}
In the same namespace as your class. (For our example, just underneath it.)
By the way, in C++ there is no need to prefix the declaration of a struct type variable with struct. This is perfect, and preferred:
_pos k1 = {0,10};
_pos k2 = {10,15};
_val v1 = {5.5};
_val v2 = {12.3};
(Though your type names are admittedly named in an unorthodox manner. :P)
Lastly, you should prefer the make_pair utility function for making pairs:
m.insert(std::make_pair(k1,v1));
m.insert(std::make_pair(k2,v2));
It saves you from having to write out the types for the pair, and is generally easier to read. (Especially when longer type names come along.)
Signature of the less than operator needs to be bool operator<(const _pos& other) const, otherwise map can not use this operator in const functions since this member function is declared as non-const.
I think that your definition of operator< is wrong - the right hand side (argument in this case) should be marked const and it should be a const member function, e.g.
bool operator<(const _pos& other) const{
return this->xi < other.xi;
}