2010-09-17 31 views
6

Próbuję napisać funkcję drukowania reprezentacji wspólnych kontenerów STL (wektor, lista itp.). Nadałem tej funkcji parametr szablonu T, który może na przykład reprezentować wektor. Mam problemy z dostaniem iterator typu T.Błąd z T :: iteratorem, gdzie parametr szablonu T może być wektorem <int> lub listą <int>

vector<int> v(10, 0); 
repr< vector<int> >(v); 

...

template <typename T> 
void repr(const T & v) 
{ 
    cout << "["; 
    if (!v.empty()) 
    { 
     cout << ' '; 
     T::iterator i; 
     for (i = v.begin(); 
      i != v.end()-1; 
      ++i) 
     { 
      cout << *i << ", "; 
     } 
     cout << *(++i) << ' '; 
    } 
    cout << "]\n"; 
} 

...

[email protected]:~/Desktop/stl$ g++ -Wall main.cpp 
main.cpp: In function ‘void repr(const T&)’: 
main.cpp:13: error: expected ‘;’ before ‘i’ 
main.cpp:14: error: ‘i’ was not declared in this scope 
main.cpp: In function ‘void repr(const T&) [with T = std::vector<int, std::allocator<int> >]’: 
main.cpp:33: instantiated from here 
main.cpp:13: error: dependent-name ‘T::iterator’ is parsed as a non-type, but instantiation yields a type 
main.cpp:13: note: say ‘typename T::iterator’ if a type is meant 

Próbowałem 'typename T :: iterator' jako sugerował kompilator, ale dostał tylko bardziej tajemniczy błąd.

Edytuj: Dzięki za pomoc! Oto wersja pracy dla każdego, kto chce korzystać z tej funkcji:

template <typename T> 
void repr(const T & v) 
{ 
    cout << "["; 
    if (!v.empty()) 
    { 
     cout << ' '; 
     typename T::const_iterator i; 
     for (i = v.begin(); 
      i != v.end(); 
      ++i) 
     { 
      if (i != v.begin()) 
      { 
       cout << ", "; 
      } 
      cout << *i; 
     } 
     cout << ' '; 
    } 
    cout << "]\n"; 
} 
+0

Co powiesz na opublikowanie również "bardziej tajemniczego" komunikatu o błędzie? –

+4

btw, możesz chcieć zamienić v.end() - 1 na coś innego niż wsparcie dla non-RandomAccess-iteratorów. – sellibitze

Odpowiedz

18

Trzeba typename aby poinformować kompilator, że ::iterator ma być rodzajem. Kompilator nie wie, że jest to typ, ponieważ nie wie, co to jest, dopóki nie utworzysz szablonu. Może na przykład odnosić się do jakiegoś statycznego elementu danych. To jest twój pierwszy błąd.

Twój drugi błąd polega na tym, że v jest referencją do const. Tak więc zamiast ::iterator musisz użyć ::const_iterator. Nie można poprosić o stały pojemnik dla niestanowiącego stałej iteracji.

+0

Kto zniweczył tę odpowiedź? Odpowiedź jest poprawna. –

+0

Nie tak bardzo, że kompilator nie wie, czym jest ':: iterator', ale standard wymaga, aby interpretować go jako nietypowy, ponieważ jest ładnie umieszczony w komunikacie o błędzie:" nazwa-zależna "' T :: iterator' jest analizowany jako nie-typ, ale tworzenie instancji daje typ " – visitor

+2

Widzę. Rozszczepienie włosów usprawiedliwia zatem upadek. – sellibitze

3

Zmień T::iterator i; do typename T::const_iterator i; ponieważ ::iterator jest typu T i v jest const &.

Przed kwalifikowanym typem zależnym potrzebujesz typename. Bez typename istnieje reguła parsowania C++, która mówi, że kwalifikowane nazwy zależne powinny być analizowane jako non-types, nawet jeśli prowadzi to do błędu składni.

typename stwierdza, że ​​poniższa nazwa powinna być traktowana jako typ. W przeciwnym razie nazwy są interpretowane w odniesieniu do nie-typów.