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.
5 answers
W list<tNode<T>*>::iterator
masz 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
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ń ()
.
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 = ...;
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.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.
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