C++ 在这个C++;模板?

C++ 在这个C++;模板?,c++,inheritance,templates,stl,C++,Inheritance,Templates,Stl,在前一段时间处理一些图形代码时,我使用int作为底层坐标保持器编写了Rect和Region类,效果很好。该区域作为STL列表的简单类扩展实现,只包含一个矩形列表 现在我还需要使用double作为底层坐标保持器的相同类型的类,并决定尝试将其模板化。因此,我基本上以一种智能的方式将“int”替换为“typename T”,并修复了这些问题 但还有一个问题让我感到困惑。我想通过对组成区域的所有矩形进行并集来计算区域的边界框。这在未模板化时可以正常工作,但在模板化时,g++会阻塞列表迭代器 以下是相关代

在前一段时间处理一些图形代码时,我使用int作为底层坐标保持器编写了Rect和Region类,效果很好。该区域作为STL列表的简单类扩展实现,只包含一个矩形列表

现在我还需要使用double作为底层坐标保持器的相同类型的类,并决定尝试将其模板化。因此,我基本上以一种智能的方式将“int”替换为“typename T”,并修复了这些问题

但还有一个问题让我感到困惑。我想通过对组成区域的所有矩形进行并集来计算区域的边界框。这在未模板化时可以正常工作,但在模板化时,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;
    }
    ...
};
//始终保持规范化的Rect类
模板
克里特类
{
公众:
//演员
克雷特(无效)
:_l(0),_t(0),_r(0),_b(0)
{
}
无效unionRect(常数K&r)
{
...
}
私人:
T(l),T,r,b ;;
};
//区域类-这是非常脑死亡
模板
类别区域:公共标准::列表
{
公众:
...
//访问者
KRect边界框(无效)
{
克里特r;
迭代器i;
对于(i=this->begin();i!=this->end();i++)
{
r、 unionRect(*i);
}
返回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
include/KGraphicsUtils.h:在成员函数“KRect KRegion::boundingBox()”中:
include/KGraphicsUtils.h:196:错误:应为“;”在“我”之前
include/KGraphicsUtils.h:197:错误:未在此作用域中声明“i”
在成员函数“KRect KRegion::boundingBox()[with T=int]”中包含/KGraphicsUtils.h:
---编辑---:111:从此处实例化
include/KGraphicsUtils.h:196:错误:依赖名称“std::foo::iterator”被解析为非类型,但实例化会生成一个类型
include/KGraphicsUtils.h:196:注意:如果类型是
我猜这是一个类型鉴定问题,有一些我不熟悉的模板y旋转。我试过各种方法,比如:

std::list< KRect<T> >::iterator i;
this->iterator i;
std::list::迭代器i;
这个->迭代器i;
但似乎什么都不管用


有什么建议吗?

迭代器
是一种依赖类型(取决于模板参数),需要在前面加上
类型名

typename std::list< KRect<T> >::iterator i;
typename std::list::迭代器i;
更好的样式是提供类范围的typedef:

template <typename T>
class KRegion : public std::list< KRect<T> >
{
    typedef std::list< KRect<T> > base;
    typedef typename base::iterator iterator;
    // ...
};
模板
类别区域:公共标准::列表
{
typedef std::listbase;
typedef typename base::迭代器迭代器;
// ...
};
我想,但我建议让区域作为成员而不是基类管理列表:

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;
    }
    ...
};
模板
克雷吉安级
{
受保护的:
typedef std::listListType;
列表类型列表;
公众:
...
//访问者
void addRect(KRect&rect){list->push_back(rect);}
...
KRect边界框(无效)
{
克里特r;
ListType::迭代器i;
对于(i=list->begin();i!=list->end();i++)
{
r、 unionRect(*i);
}
返回r;
}
...
};

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

您使用的是哪种编译器?我可以在VC++2010上编译它。他已经说过,g++-VC++传统上对没有
typename
template
的依赖名非常宽松。你永远不应该从STL容器继承,因为它们没有被认为是多态的(即没有虚拟析构函数)。正确的方法是使用作文,并适当地写出前向方法。。。虽然很乏味。同意-但这是一个概念验证的实现,必须快速编写,所以一些黑客的快捷方式是可以接受的。例如,詹姆斯,你也是一个绅士和学者!这是个好主意;但是,现在我希望客户端能够直接访问列表成员,因为我懒得编写所有访问器。:-)这是完全公平的
:)
我们都去过。只希望没有客户编写
ListType*l=new KRegion();删除l。。。