【问题标题】:How to solve ambiguity in operator overloading embedded inside a struct?如何解决嵌入在结构中的运算符重载的歧义?
【发布时间】:2016-12-29 17:25:36
【问题描述】:

在以下代码中,令人惊讶的是,g++ 编译器无法决定在将它们嵌入到结构中以用作集合中的比较器参数时使用哪个运算符:

#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);
}

这是编译器的输出:

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) {
        ^

最后几行显示了编译器显示两个候选者的歧义。

为什么存在这种歧义?我应该如何抑制它?

【问题讨论】:

  • 我在您发布的文本中没有看到“模棱两可”或类似的词。看起来你编辑了关键部分。但作为一种猜测,第二个不是const,这可能会造成混淆。
  • @Pete Becker 我刚刚对其进行了测试,您是完全正确的:看起来编译器无法决定将 const 添加到具有精确字符串参数匹配的比较对象成员还是隐式创建 @ 987654325@ 来自字符串并具有精确的函数常量匹配。
  • 制作第二个 operator() const 会消除此示例中的消息。
  • @PeteBecker 我确信是一样的(有人/某事正在编辑关键部分)但不是,it's real。看起来像 gcc 中的一个错误。并非所有 gcc 构建都这样做,

标签: c++ struct set operator-overloading


【解决方案1】:

看起来一些构建的 gcc 具有突然打印这些消息的特殊功能。例如,所有构建在 coliru do this 上。

这些消息不是错误,因为生成了目标文件,它们不是警告,因为-Werror 不会将它们变成错误。它们看起来很像编译器错误。显然,不能用编译器标志来抑制这些非警告。

在我的机器上与gcc 完全相同的版本不会打印任何带有 代码的消息。他们确实会打印带有similar code 的常规(标有彩色“警告”、不可抑制但可转为错误)警告。

在 coliru 上,制作第二个 operator() const suppresses the messages

【讨论】:

    【解决方案2】:

    两个单独的struct 中只有一个运算符专用于一个类型解决了这个问题:

    #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);
    }
    

    【讨论】:

      【解决方案3】:

      初始代码有错误:

        bool operator() (const std::string& left, const std::string& right) const {
        bool operator() (const KeyWord& left, const KeyWord& right) {
      

      在第一个声明的末尾取消const,或者在第二个声明中添加一个可以解决问题。但是,我仍然不明白为什么编译器会感到困惑。

      所以,要么:

        bool operator() (const std::string& left, const std::string& right) {
        bool operator() (const KeyWord& left, const KeyWord& right) {
      

      或:

        bool operator() (const std::string& left, const std::string& right) const {
        bool operator() (const KeyWord& left, const KeyWord& right) const {
      

      有效。

      注意:here 是否讨论了 const 函数。

      因为我想要重载,所以两个函数都应该有相同的行为,所以const 要么都要么都没有。如果我希望一个带有const 而另一个不带有不同的行为(在这种情况下我会有一些struct 成员我想修改),下面的第二个解决方案为每个操作员单独的struct定义将是解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-06-12
        • 2021-05-02
        • 1970-01-01
        • 2019-08-18
        相关资源
        最近更新 更多