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?
There was an error in the initial code:
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:
or:
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 withconst
and the other without (in the case I would have had somestruct
members I would have wanted to modify), the second solution below with separatestruct
for each operator definition would be the solution.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: