如何使我的迭代器类看起来不像容器类?

时间:2014-10-13 19:01:32

标签: c++ templates c++11 googletest

前提

假设我有一个容器类Box,它提供了内部类const_iteratoriterator。因为我希望iterator可以转换为const_iterator,后者继承自前者:

class Box {
  // ...
public:
  class const_iterator : public std::iterator<std::random_access_iterator_tag, const int> { /* ... */ };
  class iterator : public const_iterator { /* ... */ };
  // ...
};

问题

现在我想使用Google Test测试这些类。让我们声称begin()end()不会返回相同的内容:

const Box a;
EXPECT_NE(a.begin(), a.end());

向编译错误问好:

  • clang:no member named 'begin' in 'Box::const_iterator'
  • g ++:‘const class Box::const_iterator’ has no member named ‘begin’

原因

有些研究让我在Google Test源代码中this template(请点击扩展文档的链接):

typedef int IsContainer;
template <class C>
IsContainer IsContainerTest(int /* dummy */,
                            typename C::iterator* /* it */ = NULL,
                            typename C::const_iterator* /* const_it */ = NULL) {
  return 0;
}

这个模板魔术的结果是,如果EXPECT_*的参数有iteratorconst_iterator成员类,那么该类型被假定为容器类。知道了这一点,Google Test可以在预期失败时打印漂亮的人工可读报告,这很不错。

但是,有一个小细节:

// Note that we look for both C::iterator and C::const_iterator.  The
// reason is that C++ injects the name of a class as a member of the
// class itself (e.g. you can refer to class iterator as either
// 'iterator' or 'iterator::iterator').  If we look for C::iterator
// only, for example, we would mistakenly think that a class named
// iterator is an STL container.

所以,如果我理解正确的话,那就意味着

  • Box::const_iterator将自己作为名为const_iterator的成员类,将std::iterator作为名为iterator的成员类。
  • Box::iterator将自己作为名为iteratorBox::const_iterator的成员类作为名为const_iterator的成员类。

因此,我的迭代器类看起来都像是Google Test的容器类!

问题

如何设计我的迭代器类以使它们看起来不像容器?

我尝试的事情:

  • std::iterator的超级类const_iterator声明为private。这通过隐藏const_iterator成员类解决了iterator的问题,但它仍然不允许我将a.begin()作为参数传递给EXPECT_NE,除非{{1}是a。由于某种原因,Google Test似乎使用const而不是iterator begin()
  • 完全删除const_iterator begin() const超类。这是一个坏主意吗?我想我必须手动声明我的std::iterator,还有什么我不会因为不延长std::iterator_traits而失去?
  • std::iterator的超级类Box::const_iterator声明为Box::iterator。这可能是也可能不是一种选择,因为我必须重新声明我想要重用的方法(例如private)。

还有什么我忽略的吗?


示例

operator++

1 个答案:

答案 0 :(得分:1)

ThreeInts::iterator不应继承ThreeInts::const_iterator,而应单独实施。

class ThreeInts::iterator : public std::iterator< std::random_access_iterator_tag, int> { ... }
class ThreeInts::const_iterator : public std::iterator< std::random_access_iterator_tag, const int> { ... }

问题似乎是ThreeInts::const_iterator两者都有名为const_iteratoriterator的成员(也就是构造函数)。同时使iterator继承自const_iterator不是常量,因为const_iterator应该只保存指针/类似于const数据。 STL容器还将两个迭代器分开。

在该代码中,代替定义迭代器类可能就足够了,只需定义

即可
using iterator = int*;
using const_iterator = const int*;