47

次のヘッダーファイルについて考えてみます。

template <typename T> struct tNode
{
    T Data;                      //the data contained within this node
    list<tNode<T>*> SubNodes;       //a list of tNodes pointers under this tNode

    tNode(const T& theData)
    //PRE:  theData is initialized
    //POST: this->data == theData and this->SubNodes have an initial capacity
    //      equal to INIT_CAPACITY, it is set to the head of SubNodes
    {
        this->Data = theData;
        SubNodes(INIT_CAPACITY);   //INIT_CAPACITY is 10
    }

};

次に、別のファイルのコード行について考えてみます。

list<tNode<T>*>::iterator it();  //iterate through the SubNodes

コンパイラは私にこのエラーメッセージを出します:Tree.h:38:17: error: need ‘typename’ before ‘std::list<tNode<T>*>::iterator’ because ‘std::list<tNode<T>*>’ is a dependent scope

なぜコンパイラがこれを私に怒鳴っているのか私にはわかりません。

4

5 に答える 5

80

にはlist<tNode<T>*>::iterator依存する名前、つまり、テンプレートパラメータに依存する名前があります。

そのため、コンパイラーは検査できずlist<tNode<T>*>(この時点では定義がありません)list<tNode<T>*>::iterator、静的フィールドであるか型であるかを認識していません。

このような状況では、コンパイラはそれがフィールドであると想定するため、あなたの場合は構文エラーが発生します。typenameこの問題を解決するには、宣言の前にそれが型であることをコンパイラーに伝えます。

typename list<tNode<T>*>::iterator it
于 2012-06-30T16:02:00.130 に答える
22

まず、他の回答ですでに述べたように、依存型にネストされた型名の前にtypenameキーワードを付ける必要があります。

テンプレートが完全に特殊化されている場合、つまり必要がない場合、そのキーワードは必要list<tnode<int>*>::iteratorありませんが、外部クラスがテンプレートパラメータにtypename依存している場合は、が存在する必要があります。Ttypename

template <typename T> void foo() {
  list<tnode<int>*>::iterator it1; // OK without typename
  typename list<tnode<T>*>::iterator it2; // typename necessary
}

第二にtypename

typename list<tNode<T>*>::iterator it();

宣言は、イテレータではなく関数を宣言します。を削除し()ます。

于 2012-06-30T16:10:58.613 に答える
5

list<tNode<T>*>::iteratorは依存名であり、テンプレートパラメータに依存するタイプです。その変数を宣言するには、次のtypenameキーワードを使用する必要があります。

typename list<tNode<T>*>::iterator it = ...;
于 2012-06-30T15:47:52.003 に答える
2

上記の回答の詳細については、こちらをご覧ください

C++のtypenameキーワードの説明

子ノードのイテレータを:でtypedefしたかったという点で、別の、しかし同様の問題がありました。

typedef std::vector<NodeType*>::iterator ChildIterator;

同じコンパイラエラーが発生しました。ここでの提案と上記のリンクの助けを借りて、私の問題の解決策は使用することです

typedef typename std::vector<NodeType*>::iterator ChildIterator;

代わりは。

于 2015-03-13T10:12:26.067 に答える
0

イテレータは、ネストされたクラスとクラス属性にすることができます

typenameキーワードが解決するあいまいさは、 T::iterator(またはあなたの場合は) (ケース1)または(ケース2)のlist<tNode<T>*>::iteratorいずれかを参照できるということです。コンパイラーは、このような構造をデフォルトでケース2として解釈します。キーワードはケース1を強制します。nested typestatic class attributetypename

次の例は、ケース1とケース2のそれぞれの実装を示しています。どちらの場合も、行T::iterator * iter;が表示されます。typenameケース1の場合、引数を前に付けた場合にのみ有効です。ケース2の場合、それは単なるdoubleを表します(操作なし)。アスタリスク*は、ケース1の場合はポインターのインジケーターであり、ケース2の場合は乗算演算子であるため、追加されたばかりです。

最小限の再現可能な例

#include <iostream>

template <class T>
void foo1() {
    typename T::iterator * iter;
    std::cout << "foo1: iter points to: " << iter << std::endl;
}

class class1 {
    public:
        class iterator // subclass
        {
        };
};

template <class T>
void foo2() {
    double iter = 2.;
    T::iterator * iter;
    std::cout << "foo2: \"T::iterator * iter\" is a simple double: " << T::iterator * iter << std::endl;
}

class class2 {
    public:
        constexpr static double iterator = 11.;
};

int main()
{
    foo1<class1>();
    foo2<class2>();
    // foo1<class2>(); // does not compile
    // foo2<class1>(); // does not compile
    return 0;
}

出力

foo1: iter points to: 0x4010b0
foo2: "T::iterator * iter" is a simple double: 22

記事AのC++typenameキーワードの説明を指摘してくれたtrueterの功績。この答えは基本的に短いまとめです。

于 2020-09-03T11:17:04.820 に答える