Iterator szablonów C++

Rozważ następujący plik nagłówkowy:

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
    }

};

Rozważmy teraz wiersz kodu z innego pliku:

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

Kompilator podaje mi komunikat o błędzie: Tree.h:38:17: error: need ‘typename’ before ‘std::list<tNode<T>*>::iterator’ because ‘std::list<tNode<T>*>’ is a dependent scope

Nie mam pojęcia, dlaczego kompilator krzyczy na mnie za to.

Author: Adam Stelmaszczyk, 2012-06-30

5 answers

W list<tNode<T>*>::iteratormasz nazwę zależną, czyli nazwę zależną od parametru szablonu.

Jako taki kompilator nie może sprawdzić list<tNode<T>*> (w tym momencie nie ma swojej definicji), a więc nie wie, czy list<tNode<T>*>::iterator jest albo polem statycznym, albo typem.

W takiej sytuacji kompilator zakłada, że jest to pole, więc w Twoim przypadku powoduje to błąd składni. Aby rozwiązać problem, po prostu powiedz kompilatorowi, że jest to typ, umieszczając typename przed "deklaracja": {]}

typename list<tNode<T>*>::iterator it
 72
Author: akappa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-03 16:55:28

Po pierwsze, jak już wspomniano w innych odpowiedziach, nazwy typów zagnieżdżonych w typy zależne muszą być poprzedzone słowem kluczowym typename.

To słowo kluczowe nie jest potrzebne, gdy szablon jest w pełni wyspecjalizowany, co oznacza, że list<tnode<int>*>::iterator nie potrzebuje typename, ale gdy zewnętrzna klasa nadal zależy od parametru szablonuT, typename musi być obecny.

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

Po drugie, nawet z typename

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

Deklaracja zadeklaruje funkcję, a nie iterator. Usuń ().

 22
Author: AnT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-30 16:17:05

list<tNode<T>*>::iterator jest nazwą zależną, typem zależnym od parametru szablonu. Aby zadeklarować tę zmienną, należy użyć słowa kluczowego typename:

typename list<tNode<T>*>::iterator it = ...;
 5
Author: mfontanini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-30 15:58:36

Więcej informacji na temat powyższych odpowiedzi znajduje się tutaj

Opis słowa kluczowego C++ typename

Miałem inny, ale podobny problem w tym, że chciałem wpisać iterator dla węzłów potomnych z:

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

Co dało mi ten sam błąd kompilatora. Z sugestiami tutaj i pomocą powyższego linku, rozwiązaniem mojego problemu jest użycie

typedef typename std::vector<NodeType*>::iterator ChildIterator;
Zamiast tego.
 2
Author: trueter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-13 10:22:41

Iterator może być klasą zagnieżdżoną i atrybutem klasy

Wieloznaczność, którą rozwiązuje słowo kluczowe typename jest taka, że T::iterator (lub w Twoim przypadku list<tNode<T>*>::iterator) może odnosić się do nested type (przypadek 1) lub static class attribute (przypadek 2). Kompilator domyślnie interpretuje taką konstrukcję jako przypadek 2. Słowo kluczowe typename wymusza przypadek 1.

Poniższy przykład pokazuje implementację dla Przypadku 1 i przypadku 2. W obu przypadkach pojawia się linia T::iterator * iter;. W przypadku 1 jest ważne tylko z typename / align = "left" / W przypadku 2 reprezentuje tylko podwójne (bez żadnej operacji). Gwiazdka * jest po prostu dodawana, tak jak w przypadku 1 Wskaźnik dla wskaźnika, a w przypadku 2 operator mnożenia.

Minimalny powtarzalny przykład

#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;
}

Wyjście

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

Podziękowania dla trueter za wskazanie artykułu opisu słowa kluczowego C++ typename . Ta odpowiedź jest w zasadzie krótkie podsumowanie.

 0
Author: Markus Dutschke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-03 11:17:04