【问题标题】:What should the iterator type be in this C++ template?这个 C++ 模板中的迭代器类型应该是什么?
【发布时间】:2010-02-08 01:34:03
【问题描述】:

不久前在处理一些图形代码时,我使用 int 作为底层坐标持有者编写了 Rect 和 Region 类,并且效果很好。 Region 是作为 STL 列表的简单类扩展实现的,并且只包含一个 Rect 列表。

现在我还需要使用双精度对象作为底层坐标持有者的相同类型的类,并决定尝试将其模板化。所以我基本上以智能的方式将“int”替换为“typename T”并修复了问题。

但还有一个问题让我很困惑。我想通过对包含它的所有 Rect 进行联合来计算区域的边界框。这在未模板化时工作正常,但当它被模板化时,g++ 会在列表迭代器上阻塞。

以下是相关代码:

// Rect class that always remains normalized
template <typename T>
class KRect
{
public:

    // Ctors
    KRect(void)
        : _l(0), _t(0), _r(0), _b(0)
    {
    }
    void unionRect(const KRect& r)
    {
        ...
    }

private:
    T _l, _t, _r, _b;
};

// Region class - this is very brain-dead
template <typename T>
class KRegion : public std::list< KRect<T> >
{
public:
    ...

    // Accessors
    KRect<T> boundingBox(void)
    {
        KRect<T> r;
        iterator i;
        for (i = this->begin(); i != this->end(); i++)
        {
            r.unionRect(*i);
        }
        return r;
    }
    ...
};

当该代码不是模板的一部分时,因此 T 是确定的(例如 int),“迭代器 i”行可以正常工作。但是在您上面看到的内容中,Ubuntu 上的 g++ 会发出错误,我认为这些错误信息并不多:

include/KGraphicsUtils.h: In member function ‘KRect<T> KRegion<T>::boundingBox()’:
include/KGraphicsUtils.h:196: error: expected ‘;’ before ‘i’
include/KGraphicsUtils.h:197: error: ‘i’ was not declared in this scope
include/KGraphicsUtils.h: In member function ‘KRect<T> KRegion<T>::boundingBox() [with T = int]’:
--- redacted ---:111:   instantiated from here
include/KGraphicsUtils.h:196: error: dependent-name ‘std::foo::iterator’ is parsed as a non-type, but instantiation yields a type
include/KGraphicsUtils.h:196: note: say ‘typename std::foo::iterator’ if a type is meant

我的猜测是这是一个类型限定问题,带有一些我不熟悉的模板-y 旋转。我尝试了各种方法,例如:

std::list< KRect<T> >::iterator i;
this->iterator i;

但似乎没有任何效果。

有什么建议吗?

【问题讨论】:

  • 您使用的是哪个编译器?我可以在 VC++2010 上编译它。
  • 他已经说过 g++ - VC++ 传统上对于没有typenametemplate 的依赖名称非常宽松。
  • 你永远不应该从 STL 容器继承,因为它们不被认为是多态的(即没有虚拟析构函数)。正确的方法是使用组合,并适当地编写转发方法......虽然它很乏味。
  • 同意 - 但这是一个概念验证实现,必须快速编写,因此可以接受一些骇人听闻的快捷方式。

标签: c++ inheritance templates stl


【解决方案1】:

iterator 是依赖类型(它依赖于模板参数),需要以typename 为前缀:

typename std::list< KRect<T> >::iterator i;

更好的风格是提供类范围的 typedef:

template <typename T>
class KRegion : public std::list< KRect<T> >
{
    typedef std::list< KRect<T> > base;
    typedef typename base::iterator iterator;
    // ...
};

【讨论】:

    【解决方案2】:

    我认为gf has your answer,但我想建议让该区域将列表作为成员而不是基类来管理:

    template <typename T>
    class KRegion
    {
    protected:
         typedef std::list< KRect<T> > ListType;
         ListType list;
    public:
        ...
        // Accessors
        void addRect(KRect<T> & rect) { list->push_back(rect); }
        ...
        KRect<T> boundingBox(void)
        {
            KRect<T> r;
            ListType::iterator i;
            for (i = list->begin(); i != list->end(); i++)
            {
                r.unionRect(*i);
            }
            return r;
        }
        ...
    };
    

    我提出这个建议的动机是,有一天您可能想要使用不同的容器来存储您的 KRect,并且将列表作为内部成员可以让您在不破坏所有客户端代码的情况下这样做。

    【讨论】:

    • e.James,你也是绅士和学者!好主意啊;但是,现在我希望客户能够直接访问列表成员,因为我懒得写所有的访问器。 :-)
    • 完全公平:)我们都去过那里。
    • 希望没有客户写过ListType&lt;int&gt;* l = new KRegion&lt;int&gt;(); delete l;...
    猜你喜欢
    • 2012-07-01
    • 2015-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多