Шаблонный оператор == - PullRequest
       10

Шаблонный оператор ==

0 голосов
/ 16 ноября 2018

У меня есть то, что по сути является классом, содержащим 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, чтобы он сравнивал содержимое mSharedPtrMap, проверяя, чтобы объекты lhs и rhs имели одинаковое количество ключей, одинаковые ключи и одни и те же объекты, а это означает, что == оператор ключей / объектов оценивается как true?

1 Ответ

0 голосов
/ 16 ноября 2018

Если вы набираете erase (и позже не знаете, какой тип вы сохранили ранее), тогда все функции должны быть предоставлены интерфейсом базового класса. Итак, нам нужен виртуальный operator== in A, который реализован в каждом 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;
};

Демо с тестами

Примечание. Я не исправил все несоответствия в исходном коде. (Вы хотите переместить или скопировать конструкцию T? Зачем хранить const объекты, если оператор сравнения MyClass не const?)

...