2016-07-30 34 views
7

Chciałbym poprosić o pomoc z poprawną składnią, aby zadeklarować std :: map, której mapowany typ jest wewnętrzną klasą klasy szablonu.Poprawna składnia dla iteratora odwzorowania klasy wewnętrznej klasy szablonu?

Proszę znaleźć w kodzie poniżej blok # if/# else. Blok "#if 1" ma klasę zewnętrzną, która zawiera wewnętrzną klasę wewnętrzną. Zewnętrzna definiuje funkcję Func, która pobiera std map, której typ_aplikacji jest typu Inner.

#include <map> 

#if 1 
template<typename C, typename T> 
class Outer 
{ 
    public: 
     Outer(const C& c, const T& t){} 
     virtual ~Outer(){} 

     class Inner 
     { 
      public: 
       Inner(){} 
       Inner(T t){} 
       virtual ~Inner(){} 

      protected: 
       T mT; 
     }; 

     void Func(std::map<C, Inner>& rMap); 

    protected: 
     std::map<C, Inner> mMap; 
}; 

template<typename C, typename T> 
void Outer<C, T>::Func(std::map<C, Outer::Inner>& rMap) 
{ 
    std::map<C, Inner>::iterator iter; 

    for (iter = rMap.begin(); iter != rMap.end(); ++iter) 
    { 
     mMap[iter->first] = iter->second; 
    } 
} 

#else 

class Outer 
{ 
    public: 
     Outer(const int& i, const double& d){} 
     virtual ~Outer(){} 

     class Inner 
     { 
      public: 
       Inner() : mD(0){} 
       Inner(const double d) : mD(d){} 
       virtual ~Inner(){} 

      protected: 
       double mD; 
     }; 

     void Func(std::map<int, Inner>& rMap); 

    protected: 
     std::map<int, Inner> mMap; 
}; 

void Outer::Func(std::map<int, Inner>& rMap) 
{ 
    std::map<int, Inner>::iterator iter; 

    for (iter = rMap.begin(); iter != rMap.end(); ++iter) 
    { 
     mMap[iter->first] = iter->second; 
    } 
} 

#endif 

int main() 
{ 
    return 0; 
} 

kompilacja zawodzi w Outer :: Func (...) w deklaracji std :: map iterator, czyli tej linii:

std::map<C, Inner>::iterator iter; 

Próbowałem, ale nie można dowiedzieć się, co jest źle z linią kodu.

Dla porównania/kontrastu blok "#else" zawiera kod non-template o podobnym charakterze. Ten kod się kompiluje.

Błąd kompilacji i g ++ wersja to:

>g++ main.cpp 
main.cpp: In member function ‘void Outer<C, T>::Func(std::map<C, Outer<C, T>::Inner, std::less<_Key>, std::allocator<std::pair<const C, Outer<C, T>::Inner> > >&)’: 
main.cpp:31: error: expected ‘;’ before ‘iter’ 
main.cpp:33: error: ‘iter’ was not declared in this scope 

>g++ --version 
g++ (GCC) 4.4.7 20120313 (Red Hat 4.4.7-11) 
Copyright (C) 2010 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 

Dziękuję za wszelką pomoc.

+0

'nazwa-pliku std :: map :: iterator iter;' – nshct

+0

Możliwy duplikat [Gdzie i dlaczego muszę umieścić słowa kluczowe "szablon" i "typename"?] (Http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords) – Oktalist

Odpowiedz

9

Od Inner jest członkiem Twojego szablonu Owner<C, T>, staje się dependent name. To powoduje, że identyfikator iterator, który w tym przypadku jest członkiem std::map<C, Inner>, również staje się nazwą zależną.

Zmusza cię do używania słowa kluczowego typename, zgodnie z zasadami:

typename std::map<C, Inner>::iterator iter; 
~~~^~~~~ 

To dlatego, że kompilator nie może być pewien, co niektóre konstrukcje wewnątrz swojej klasie na myśli, ponieważ nie robi wiem dokładnie rodzaje wykorzystywanych do C i T jeszcze:

Wewnątrz definicji szablonu (obie klasy szablonu i szablonu funkcja), o sens Niektóre konstrukcje mogą się różnić w zależności od instancji. W szczególności typy i wyrażenia mogą zależeć od typów parametrów szablonu typu i wartości parametrów szablonu non-type.

Słowo kluczowe typename służy do informowania kompilatora, że ​​symbol, do którego uzyskuje dostęp, jest rzeczywiście aliasem/typem.

+1

Wciąż jestem zdumiony fontem mądrości, który tam jest. Dziękuję Ci. – StoneThrow

+0

Szczerze mówiąc, wyjaśnienie pod linkiem, który zauważyłeś, przekroczyło moją głowę. Jeśli znasz ten scenariusz, czy mógłbyś wyjaśnić to w prostszy sposób? Kiedy mówisz "Słowo kluczowe nazwa_pliku służy do informowania kompilatora, że ​​symbol, do którego uzyskujesz dostęp, jest rzeczywiście aliasem/typem", co to jest "symbol" w tym kontekście? Wewnętrzna klasa? W oparciu o moje parsowanie wyjaśnień, nie jestem pewien, dlaczego to rozwiązanie jest wymagane w tej sytuacji (klasy wewnętrzne), ale nie jest wymagane w przypadku klas "nie-wewnętrznych". Doceń, jeśli masz głębsze wytłumaczenie, ale nie martw się, jeśli nie. Dziękuję Ci. – StoneThrow