我想继承容器类的迭代器。它应始终具有与实际实现无关的相同签名。
但我遇到的问题是ContainerImpl
Container::Iterator
从[{1}}返回的ContainerImpl::begin()
将被覆盖的方法从ContainerImpl::Iterator
切换回Container::Iterator
的方法。
如何强制使用更具体的方法? 或者我可以重写我的类,使其表现得像那样吗?
以下是一个工作示例。它至少可以编译成C ++ 17。
#include <tuple>
using std::tuple;
class Container {
// some code
public:
class Iterator {
public:
virtual tuple<int, int> &operator*() {};
virtual Iterator &operator++() {};
virtual bool operator!=(const Iterator &rhs) const {};
};
virtual Iterator begin() = 0;
virtual Iterator end() = 0;
};
class ContainerImpl : public Container {
// some code
public:
class Iterator : public Container::Iterator {
public:
Iterator(ContainerImpl &containerImpl) {
// init
}
Iterator() {
// end_iterator
}
virtual tuple<int, int> &operator*() override {
// impl
};
virtual Container::Iterator &operator++() override {
// impl
};
virtual bool operator!=(const Container::Iterator &rhs) const override {
// impl
};
};
virtual Container::Iterator begin() override {
return Iterator{*this};
};
virtual Container::Iterator end() override {
return Iterator{};
};
};
int main() {
ContainerImpl cont{};
for (auto &entry : cont) {
// here Container::Iterator::operator++() is called
// instead of ContainerImpl::Iterator::operator++()
}
}
编辑:
谢谢!我读完了你的评论并发现我应该尝试使用模板的静态方法。性能对于那些迭代器来说非常重要。这将需要重构我使用此代码的其他代码。但它应该是温和的。
以下是我提出的建议:
#include <tuple>
#include <type_traits>
using std::tuple;
template<class SubContainer>
class Container;
template<class ContImpl>
class Iterator {
static_assert(std::is_base_of<Container<ContImpl>, ContImpl>::value, "ContImpl not derived from Container");
public:
tuple<int, int> &operator*();
Iterator<ContImpl> &operator++();
bool operator!=(const Iterator<ContImpl> &rhs) const;
};
template<class SubContainer>
class Container {
public:
Iterator<SubContainer> begin();
Iterator<SubContainer> end();
};
class ContImpl;
template<>
class Iterator<ContImpl> {
public:
ContImpl &container;
Iterator(ContImpl &container, bool is_end = false) : container(container) { init(); }
void init() {
}
tuple<int, int> &operator*() {
}
Iterator<ContImpl> &operator++() {
}
bool operator!=(const Iterator<ContImpl> &rhs) const {
}
};
class ContImpl : public Container<ContImpl> {
public:
Iterator<ContImpl> begin() {
return Iterator<ContImpl>(*this, false);
}
Iterator<ContImpl> end() {
return Iterator<ContImpl>(*this, true);
}
};
int main() {
ContImpl cont{};
for (auto &entry : cont) {
// Iterator<ContImpl>::operator++() is called.
}
}
答案 0 :(得分:0)
如果你想动态地抽象出std::list<int>
和std::vector<int>
之间的差异,那么你想要的是type erasure。但请注意,使用模板模板参数之类的东西,也可以静态抽象具有相似接口(具有相同或不同元素类型)的容器,这些(如果它符合您的要求)应该要快得多。
关于基于模板的方法:虽然它可能具有文档的价值,但Container
中的方法是不必要的:静态多态性不需要任何“基本函数”来覆盖。如果删除它们,则可以完全不使用该CRTP类。然后,类似地,您可以使用简单的类Iterator
替换ContImpl::iterator
类模板。
当然,此时剩下的就是标准容器之间的接口兼容性相同(允许代码如
template<template<class> class C>
C<int> makeInts(/*...*/);
void f() {
auto d=makeInts<std::deque>(/*...*/);
// ...
}
我在上面建议)。有趣的练习是隐藏包装类后面的不同的容器接口或者使用traits接口。