我在开发优化求解器时遇到了问题Uno。
我定义了一个抽象类
Collection
,它表示一组可以迭代的整数:一个向量、一个数值范围(一组整数 {a, a+1, ..., b})、现有的符号串联整数集等get_bounded_variables()
,其返回类型为 const Collection&
,我可以使用自定义 for_each
函数对其进行迭代(请参阅此处):
problem.get_bounded_variables().for_each([&](size_t index) {
...
});
不同类型的问题对
get_bounded_variables()
的定义不同。
它确实有效,但我宁愿使用更经典的语法和基于范围的 for 循环。
现在,我的问题是,如果我想写这样的东西:
for (size_t index: problem.get_bounded_variables()) {
...
}
我需要为抽象
begin()
定义 end()
和 Collection
函数,但它的子类具有不同的迭代器类型。
所以在那一点上我陷入了困境,我不确定这是否可行。我刚刚读到有关使用自由函数 begin(const Collection&)
和 end(const Collection&)
,但我认为这对我没有帮助。查理
您正在寻找的技术称为“类型擦除”。由于许多技术细节,STL 兼容的类型擦除迭代器的完整实现很长,但对于基于 for
的循环,实现
operator*
、operator++
和 operator!=
就足够了。这是一个最小的例子:class Iterator {
public:
template<class It>
Iterator(It it) : impl_(std::make_unique<Impl<It>>(it)) {}
std::size_t operator*() const {
return impl_->deref();
}
Iterator& operator++() {
impl_->increment();
return *this;
}
friend bool operator!=(const Iterator& it1, const Iterator& it2) {
return !it1.impl_->equal(*it2.impl_);
}
private:
class Base {
public:
virtual ~Base() = default;
virtual std::size_t deref() const = 0;
virtual void increment() = 0;
virtual bool equal(const Base&) const = 0;
};
template<class It>
class Impl : public Base {
public:
Impl(It it) : it_(it) {}
std::size_t deref() const override {
return *it_;
}
void increment() override {
++it_;
}
bool equal(const Base& other) const override {
return it_ == dynamic_cast<const Impl&>(other).it_;
}
private:
It it_;
};
private:
std::unique_ptr<Base> impl_;
};
这是一个如何使用这个类型擦除迭代器的示例:
class Collection {
public:
// ...
virtual Iterator begin() const = 0;
virtual Iterator end() const = 0;
};
class VecCollection: public Collection {
public:
// ...
Iterator begin() const override {
return vec_.begin();
}
Iterator end() const override {
return vec_.end();
}
private:
std::vector<std::size_t> vec_;
};
void print(const Collection& c) {
for (std::size_t i : c)
std::cout << i << ' ';
}
int main() {
VecCollection vc(std::vector<std::size_t>{1, 2, 3, 4, 5});
print(vc);
}