5


1

このC ++テンプレートでは、イテレータタイプは何にすべきですか?

しばらく前にいくつかのグラフィックコードで作業しているときに、基になる座標ホルダーとしてintを使用してRectクラスとRegionクラスを記述しましたが、それはうまくいきました。 Regionは、STLリストの単純なクラス拡張として実装されており、Rectのリストのみが含まれています。

また、基になる座標ホルダーとしてdoubleを使用する同じ種類のクラスが必要になったので、テンプレート化を試みることにしました。 したがって、基本的に「int」を「typename T」にインテリジェントな方法で置き換え、問題を修正しました。

しかし、私が困惑している1つの問題が残っています。 リージョンの境界ボックスを計算するには、それを構成するすべてのRectsを結合します。 テンプレート化されていない場合は正常に動作しますが、テンプレート化されている場合、g ++はリストイテレータで停止します。

関連するコードは次のとおりです。

// Rect class that always remains normalized
template
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
class KRegion : public std::list< KRect >
{
public:
    ...

    // Accessors
    KRect boundingBox(void)
    {
        KRect 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 KRegion::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 KRegion::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 >::iterator i;
this->iterator i;

しかし、何もうまくいかないようです。

助言がありますか?

2 Answer


9


iterator`は依存型(テンプレート引数に依存)であり、接頭辞として typename`が必要です:

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

より良いスタイルは、クラス全体のtypedefを提供することです:

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


3


gfが答えを持っていますと思いますが、リージョンにベースクラスではなくメンバーとしてリストを管理させることを提案します:

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

この提案の動機は、ある日、KRectを保存するために別のコンテナーを使用したい場合があり、内部メンバーとしてリストを持つことで、すべてのクライアントコードを壊すことなくそうすることができます。