【发布时间】:2017-07-24 17:29:32
【问题描述】:
我通常会遇到这样的情况:我引入一个抽象基类(称为Foo)来将不同子类的实例(称为Bar 和Baz)存储在一个容器中(例如std::vector<std::unique_ptr<Foo>>) .为了便于说明,我将这些示例类放在这里:
class Foo {
public:
virtual int getId() const = 0;
};
class Bar : public Foo {
public:
Bar(int id) : id_(id) {}
int getId() const override { return id_; }
private:
int id_;
};
class Baz : public Foo {
public:
Baz(int id) : id_(id) {}
int getId() const override { return id_; }
private:
int id_;
};
如果我实现一个函数来迭代std::vector<std::unique_ptr<Foo>>,它看起来像
template<class InputIterator>
void printIds(InputIterator first, InputIterator last) {
for (; first != last; ++first)
std::cout << (*first)->getId() << std::endl;
}
但是,如果我还想允许迭代 homogeneous 类型的向量(例如,std::vector<Bar>)而不重写整个函数(或可能的其他类似类型的函数)怎么办?我看到了两种明显的可能性:
1) 实现功能
template<class Type>
const Type & dereference(const Type &value) {
return value;
}
template<class Type>
const Type & dereference(const std::unique_ptr<Type> &value) {
return *value;
}
替换
std::cout << (*first)->getId() << std::endl;
通过
std::cout << dereference(*first).getId() << std::endl;
2) 实现功能
template<class Type>
int getId(const Type &value) {
return value.getId();
}
template<class Type>
int getId(const std::unique_ptr<Type> &value) {
return value->getId();
}
替换
std::cout << (*first)->getId() << std::endl;
通过
std::cout << getId(*first) << std::endl;
选项 1) 似乎可以统一处理Type &(或const Type &)和std::unique_ptr<Type>(甚至Type * 或const Type *)类型的引用。但是,我还没有看到这在生产代码中被大量使用。这是避免代码重复的常见模式吗?还是有更好的方法来处理这个问题?
【问题讨论】:
-
"这是避免代码重复的常见模式吗?" 不,因为人们通常不需要使用迭代指针容器然后生成的函数它遍历一个非指针容器。
-
我的答案是使用选项 1。创建一个“get”函数,该函数具有处理值和类指针类型的重载。
-
您是否考虑过间接迭代器包装器,例如boost::indirect_iterator?
-
@JesperJuhl 是的,你是。 OP 希望统一迭代指针容器和项目容器中的 pointed to 元素。
-
我怀疑为两种迭代使用相同的代码对您来说实际上很重要。你确定你不是仅仅因为它“感觉正确”而不是为了获得有意义的东西而试图在这里进行微优化吗?看看@NicolBolas 怎么说。