Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
217 views
in Technique[技术] by (71.8m points)

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

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...