【问题标题】:Templated operator ==模板化运算符 ==
【发布时间】:2018-11-16 12:16:16
【问题描述】:

我有一个本质上包含 std::map 的类,其中值是 shared_ptrs 包装一个包含不同类型的容器。骨架代码如下:

// Just a basic example class
class MyClass {
  public:
    explicit MyClass(int i) : mI(i) {}
    bool operator==(const MyClass& rhs) { return mI == rhs.mI; }
  private:
    int mI;
};

// A class into which key value pairs can be added where the value
// can be of a different type.
class MultipleTypeMap {

 public:

   template <typename T>
   void AddObject(const std::string& key, const T object) {
     auto ptr = make_shared<B<MyClass>>(std::move(object));
     mSharedPtrMap.insert(pair<string, shared_ptr<A>>("key", ptr));
   }
   // ...

 private:

    class A {
    public:
      virtual ~A() = default;
    };

    template<typename T>
    class B : public A {
    public:
      explicit B(const T& t) : item(t) {}
      const T item;
    };

    map<string, shared_ptr<A>> mSharedPtrMap;
};

int main() {

    MyClass m(1);
    MultipleTypeMap multiMap;
    multiMap.AddObject("test", m);

    MyClass n(1);
    MultipleTypeMap multiMap2;
    multiMap2.AddObject("test", n);

    if (multiMap == multiMap2) {
        cout << "Equal" << endl;
    }

    return 0;
}

应如何编写 MultipleTypeMap 的通用 == 运算符,以便通过检查 lhs 和 rhs 对象是否具有相同数量的键、相同的键和相同的对象来比较 mSharedPtrMap 的内容,其中相同意味着== 键/对象的运算符计算结果为 true?

【问题讨论】:

  • 这是一个非常令人困惑的人为示例。 1、std::map不能插入多个相同的key。 2.你从来没有真正使用过string key,你总是用"key"插入。你到底想达到什么目的?
  • 一旦你用类型擦除了你的T,要找回类型就不是那么容易了。您显然无法在编译时选择正确的比较运算符,因此您需要一些运行时调度,或者通过虚拟函数或一些手动 typeid 恶作剧。你看过std::any吗?
  • @FantasticMrFox 我同意。由于要解决的问题,甚至可能无法编译的实际代码示例将更加平易近人。当前的问题太多了,很难说哪个是要回答的问题。

标签: c++ c++11 operator-overloading


【解决方案1】:

如果你输入了erase(后来不知道你之前存储的类型),那么所有的功能都必须由基类接口提供。所以,我们需要在A 中实现一个虚拟的operator==,并在每个B 中实现。

这是一个实现:

class MultipleTypeMap {

 public:
   template <typename T>
   void AddObject(const std::string& key, T object) {
     auto ptr = std::make_unique<B<T>>(std::move(object));
     mMap.emplace(key, std::move(ptr));
   }
   // ...

    bool operator==(const MultipleTypeMap& other) const
    {
        // Sizes must be equal.
        if (mMap.size() != other.mMap.size())
            return false;

        // Sizes are equal, check keys and values in order.
        auto itOther = other.mMap.begin();
        for (auto it = mMap.begin(); it != mMap.end(); ++it, ++itOther)
        {
            if (it->first != itOther->first)
                return false;
            if (*it->second != *itOther->second)
                return false;
        }
        // No differences found.
        return true;
    }
    bool operator!=(const MultipleTypeMap& rhs) const { return !(*this == rhs); }

 private:

    class A {
    public:
      virtual ~A() = default;

      virtual bool operator==(const A& other) const = 0;
      bool operator!=(const A& other) const { return !(*this == other); }
    };

    template<typename T>
    class B : public A
    {
    public:
        explicit B(const T& t) : item(t) {}

        bool operator==(const A& other) const override
        {
            const B<T>* otherB = dynamic_cast<const B<T>*>(&other);
            // If the cast fails, types are different.
            if (!otherB)
                return false;
            // Note: The above is probably slow, consider storing (on construction)
            // and checking typeids instead.

            // Check item equality.
            return item == otherB->item;
        }

        const T item;
    };

    std::map<std::string, std::unique_ptr<A>> mMap;
};

Demo with tests

注意:我没有修复原始代码中的所有不一致之处。 (你想移动还是复制构造你的T?当你的MyClass比较运算符不是const时,为什么要存储const对象?)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-06
    • 1970-01-01
    • 2020-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多