擦除容器类型的运算符==

operator== of a type erased container

考虑以下 class 包装一个 容器 type-erase 它的类型:

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== 添加到 class C
在内部,它应该简单地在底层容器上调用相同的运算符,但我被困在这个问题上,因为我不知道该怎么做。
这个想法是,如果 C 的底层容器 return true.

operator== 两个实例相等

无论我到现在为止尝试过什么,我最终都无法获得两个底层容器之一的类型,主要是 other.[=25 之一=] 有没有我目前看不到的简单解决方案,或者我应该放弃?

假设您希望在比较两个不同的容器时 return 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()); }
};

尽管 juanchopanza 提出了很好的建议,但我发现,就底层容器表示相同的概念(例如,矢量的不同特化)而言,也许有不需要 type-erased 迭代器。

下面是依赖于 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);
}

欢迎批评指正,希望这个回答能对其他网友有所帮助。 :-)