代码之家  ›  专栏  ›  技术社区  ›  bourne

关于操作员超载的澄清

  •  -1
  • bourne  · 技术社区  · 1 年前

    为了提供上下文,我有一个依赖于另一个Foo库的可执行文件,该库为Identifier类提供实现,现在我的可执行程序中的模块类需要缓存以Identifier为键的Foo对象,因此我添加了如下所示的逻辑

    class Module {
    public:
        
        static std::shared_ptr<Module> create();
    
        explicit Module() = default;
    
        ...
    protected:
        ...
        /// Map that caches Foo object keyed on @c Identifier.
        std::map<Identifier,Foo> m_FooMap;
    };
    

    在我的模块中。CPP我插入地图如下
    Foo foo; m_FooMap.emplace(identifier, foo); 但当我尝试编译时,我得到了以下错误

    /local/home/workspace/build/usr/include/c++/v1/__functional/operations.h:372:21: error: invalid operands to binary expression ('const Identifier' and 'const Identifier')
            {return __x < __y;}
                    ~~~ ^ ~~~
    /local/home/workspace/build/usr/include/c++/v1/map:598:17: note: in an instantiation of member function 'std::less<Identifier>::operator()' requested here
            {return static_cast<const _Compare&>(*this)(__x, __y.__get_value().first);}
                    ^
    /local/home/workspace/build/usr/include/c++/v1/__tree:1974:17: note: in instantiation of member function 'std::__map_value_compare<Identifier, Foo>, std::less<Identifier>, true>::operator()' requested here
                if (value_comp()(__v, __nd->__value_))
                    ^
    

    据我所知,Identifier类似乎缺少小于运算符,由于我无法对提供Identifier实现的Foo库进行更改,我试图在Module.h文件本身中为Identifier重载小于和等于运算符

    // Overloading the less-than operator for the Identifier
    // objects
    bool operator<(const Identifier& lhs, const Identifier& rhs){
        return (lhs.field1 < rhs.field1);
    }
    
    // Overloading the equal to the operator for the Identifier
    // objects
    bool operator==(const Identifier& lhs, const Identifier& rhs){
        return (lhs.field1 == rhs.field1);
    }
    

    但我仍然看到同样的错误。因此,我想澄清我的理解是否正确,即标识符类的缺失程度低于运算符重载,一旦提供,我们就可以基于标识符进行密钥设置。此外,由于我无法修改Foo库中提供Identifier类的逻辑,我可以提供如上所示的Identifier类自定义运算符重载吗?或者这不可行吗?如果可行,有什么替代方案?

    1 回复  |  直到 1 年前
        1
  •  2
  •   Jerry Coffin    1 年前

    至少在我读到的时候,你目前的情况大致是这样的:

    #include <string>
    #include <map>
    
    // defined in some other file, but class definition included via a header:
    namespace library { 
        class Identifier {
        public:
            Identifier(std::string const &s) : data(s) {}
    
            explicit operator std::string() const { return data; }
            std::string data;
        };
    }
    
    bool operator<(library::Identifier const &a, library::Identifier const &b) { 
        return a.data < b.data;
    }
    
    class Module {
        std::map<library::Identifier, int> data;
    public:
        void insert(library::Identifier const &s, int i) { 
            data[s] = i;
        }
    };
    
    int main() { 
    
        Module m;
        library::Identifier i("foo");
    
        m.insert(i, 1);
    }
    

    你有 Identifier 由某个库定义。在你自己的课堂上,你有一个 map 试图使用 标识符 作为关键。自从 标识符 本身没有定义 operator< ,你自己定义了一个。但它仍然没有找到,编译仍然失败,就像你没有定义一样 操作员< 完全。

    我已经定义了 标识符 在名称空间内,因为我相当肯定你的代码就是这样。更重要的是,它位于名称空间中是编译器找不到也不会使用您定义的运算符的真正原因。

    幸运的是,解决这个问题相当容易。您需要将运算符放在与相同的命名空间中 标识符 其本身被定义为:

    #include <string>
    #include <map>
    
    // defined in some other file, but class definition included via a header:
    namespace library { 
        class Identifier {
        public:
            Identifier(std::string const &s) : data(s) {}
    
            explicit operator std::string() const { return data; }
            std::string data;
        };
    }
    
    namespace library {
    bool operator<(library::Identifier const &a, library::Identifier const &b) { 
        return a.data < b.data;
    }
    }
    
    class Module {
        std::map<library::Identifier, int> data;
    public:
        void insert(library::Identifier const &s, int i) { 
            data[s] = i;
        }
    };
    
    int main() { 
    
        Module m;
        library::Identifier i("foo");
    
        m.insert(i, 1);
    }
    

    有了这个,代码编译得很好。