我有以下代码,表示3D应用程序中的网格(为清晰起见,省略了一些代码):
class Mesh {
public:
typedef std::vector<Vertex> Vertices;
typedef std::vector<int> Elements;
template<class VerticesIt, class ElementsIt>
Mesh(const VerticesIt verticesBegin,
const VerticesIt verticesEnd,
const ElementsIt elementsBegin,
const ElementsIt elementsEnd) :
vertices_(verticesBegin, verticesEnd),
elements_(elementsBegin, elementsEnd) {
}
virtual ~Mesh();
typename Vertices::const_iterator verticesBegin() const {
return vertices_.begin();
};
typename Vertices::const_iterator verticesEnd() const {
return vertices_.end();
};
typename Elements::const_iterator elementsBegin() const {
return elements_.begin();
};
typename Elements::const_iterator elementsEnd() const {
return elements_.end();
};
private:
Vertices vertices_;
Elements elements_;
};
它工作得非常好,为内部数据提供了清晰的界面。没有公开容器的实现细节。
但是,我对此有一点打嗝。我不能使用基于范围的循环,必须使用迭代器:for (auto it = mesh.verticesBegin(); it != mesh.verticesEnd(); ++it) {
// Do stuff
}
for (auto it = mesh.elementsBegin(); it != mesh.elementsEnd(); ++it) {
// Do stuff
}
我的口味有点冗长。我首选的客户端代码将如下所示:
for(auto & vert : mesh.vertices) {
// Do stuff.
}
for(auto & element : mesh.elements) {
// Do stuff.
}
是否有可能实现没有暴露容器的实现细节?另外,我不想将容器包装到自定义类中,因为我想要在Mesh类中完全访问所选容器(std :: vector)。
答案 0 :(得分:9)
您可以使用某种代理,例如:
template<typename Container>
class ConstIteratorProxy
{
public:
ConstIteratorProxy(const Container& container) : container_(container) { }
typename Container::const_iterator begin() const {
return container_.begin();
};
typename Container::const_iterator end() const {
return container_.end();
};
private:
const Container& container_;
};
在Mesh中:
ConstIteratorProxy<Vertices> vertices() const {
return ConstIteratorProxy<Vertices>(vertices_);
}
ConstIteratorProxy<Elements> elements() const {
return ConstIteratorProxy<Elements>(elements_);
}
然后使用它:
Mesh m;
for (auto& v : m.vertices()) { }
for (auto& e : m.elements()) { }
答案 1 :(得分:2)
将您的功能verticesBegin
和verticesEnd
分别重命名为begin
和end
。然后你就可以这样写:
for(auto & vert : mesh)
{
// Do stuff.
}
请注意,基于范围的for
循环期望您的收件人具有begin
和end
作为成员函数 - 或者自由函数begin
和end
你的容器作为参数。
另请注意,基于范围的for循环不能迭代两件事 - mesh
可以表现得像一个单独的容器,而不是两个容器。因此,如果你想迭代索引,那么你就要暴露它,或者抽象它然后再显示顶点。
或者你可以编写一个zip迭代器,它将在一个for循环中同时迭代两个容器。
答案 2 :(得分:0)
使用代理存储两个迭代器并实现begin和end方法非常容易:
#include <iostream>
#include <vector>
template <typename T>
struct PairIt {
PairIt(T&& b, T&& e) : b_{std::forward<T>(b)}, e_{std::forward<T>(e)} {}
T begin() const { return b_; }
T end() const { return e_; }
private:
T b_,e_;
};
std::vector<int> badglobal { 1, 2, 3 };
PairIt<std::vector<int>::iterator> ForRangeProxy() {
return { begin(badglobal), end(badglobal) };
};
int main() {
for( auto v : ForRangeProxy() )
std::cout << v << std::endl;
}
您可以为对象想要授予访问权限的每个集合实现多个ForRangeProxy
。
答案 3 :(得分:0)
您可以从vertices()
和elements()
函数返回迭代器包装器,您可以将它传递给for循环,例如。
template<typename T>
class iterator_wrapper
{
public:
iterator_wrapper(const typename std::vector<T>::const_iterator &begin_,
const typename std::vector<T>::const_iterator &end_)
:m_begin(begin_), m_end(end_) {}
typename std::vector<T>::const_iterator begin() const {return m_begin;}
typename std::vector<T>::const_iterator end() const {return m_end;}
private:
typename std::vector<T>::const_iterator m_begin, m_end;
};
在网格类中定义vertices()
和elements()
函数:
iterator_wrapper<Vertex> vertices() {return iterator_wrapper<Vertex>(vertices_.begin(), vertices_.end());}
iterator_wrapper<int> elements() {return iterator_wrapper<int>(elements_.begin(), elements_.end());}
然后称之为:
for(auto &vert:mesh.vertices())
{
//....
}
for(auto &element:mesh.elements())
{
//....
}