оператор= = типа стертого контейнера
Рассмотрим следующий класс, который обертывает контейнер и type-erase s его тип:
class C final {
struct B {
virtual bool empty() const noexcept = 0;
};
template<class T, class A>
struct D: public B {
// several constructors aimed to
// correctly initialize the underlying container
bool empty() const noexcept override { return v.empty(); }
private:
std::vector<T, A> v;
};
// ...
public:
//...
bool operator==(const C &other) const noexcept {
// ??
// would like to compare the underlying
// container of other.b with the one
// of this->b
}
private:
// initialized somehow
B *b;
};
Я хотел бы добавить operator==
в класс C
.
Внутренне он должен просто вызвать тот же оператор для нижележащих контейнеров, но я застрял на этой проблеме, потому что не знаю, как это сделать.
Идея заключается в том, что два экземпляра C
равны, если operator==
их нижележащих контейнеров возвращают true
.
Что бы я ни пробовал до сих пор, я всегда заканчивал будучи неспособным получить тип одного из двух нижележащих контейнеров, главным образом один из другого.
Есть ли простое решение, которое я не вижу в данный момент, или я должен сдаться?
2 ответа:
Несмотря на хорошее предложение от juanchopanza, я обнаружил, что, насколько глубинные контейнеры представляют одно понятие (например, разных специализаций вектора), может быть, нет необходимости тип-сотриД итератора.
Ниже приведена возможная реализация, которая опирается на
operator[]
иsize
Метод-член:#include <vector> #include <cassert> class Clazz final { struct BaseContainer { virtual std::size_t size() const noexcept = 0; virtual int operator[](std::size_t) const = 0; virtual void push_back(int) = 0; }; template<class Allocator> struct Container: public BaseContainer { Container(Allocator alloc): v{alloc} { } std::size_t size() const noexcept override { return v.size(); } int operator[](std::size_t pos) const override { return v[pos]; } void push_back(int e) override { v.push_back(e); } private: std::vector<int, Allocator> v; }; public: template<class Allocator = std::allocator<int>> Clazz(const Allocator &alloc = Allocator{}) : container{new Container<Allocator>{alloc}} { } ~Clazz() { delete container; } void push_back(int e) { container->push_back(e); } bool operator==(const Clazz &other) const noexcept { const BaseContainer &cont = *container; const BaseContainer &oCont = *(other.container); bool ret = (cont.size() == oCont.size()); for(std::vector<int>::size_type i = 0, s = cont.size(); i < s && ret; i++) { ret = (cont[i] == oCont[i]); } return ret; } bool operator!=(const Clazz &other) const noexcept { return !(*this == other); } private: BaseContainer *container; }; int main() { Clazz c1{}, c2{}, c3{}; c1.push_back(42); c2.push_back(42); assert(c1 == c2); assert(c1 != c3); }
Открыт для критики, надеясь, что этот ответ поможет другим пользователям. :- )
Предполагая, что вы хотите вернуть false при сравнении двух разных контейнеров, это должно сделать работу (осторожно: непроверено):
class Container { struct Concept { virtual ~Concept() = default; virtual Concept* clone() const = 0; virtual bool equals(Concept const*) const = 0; }; template<typename T> struct Model final : Concept { Model(T t) : data{std::move(t)} {} Model* clone() const override { return new Model{*this}; } virtual bool equals(Concept const* rhs) const override { if (typeid(*this) != typeid(*rhs)) return false; return data == static_cast<Model const*>(rhs)->data; } T data; }; std::unique_ptr<Concept> object; public: template<typename T> Container(T t) : object(new Model<T>{std::move(t)}) {} Container(Container const& that) : object{that.object->clone()} {} Container(Container&& that) = default; Container& operator=(Container that) { object = std::move(that.object); return *this; } friend bool operator==(Container const& lhs, Container const& rhs) { return lhs.object->equals(rhs.object.get()); } };