Dlaczego muszę używać typedef typename w g++, ale nie VS?

Minęło trochę czasu, odkąd GCC złapało mnie z tym, ale stało się to dzisiaj. Ale nigdy nie rozumiałem, dlaczego GCC wymaga typedef typename w szablonach, podczas gdy VS i chyba ICC nie. czy typedef typename jest "błędem" lub nadmiernym standardem, czy czymś, co pozostawiono twórcom kompilatora?

Dla tych, którzy nie wiedzą co mam na myśli tutaj jest próbka:

template<typename KEY, typename VALUE>
bool find(const std::map<KEY,VALUE>& container, const KEY& key)
{
    std::map<KEY,VALUE>::const_iterator iter = container.find(key);
    return iter!=container.end();
}

Powyższy kod kompiluje się w VS (i prawdopodobnie w ICC), ale zawodzi w GCC, ponieważ chce go TAK:

template<typename KEY, typename VALUE>
bool find(const std::map<KEY,VALUE>& container, const KEY& key)
{
    typedef typename std::map<KEY,VALUE>::const_iterator iterator; //typedef typename
    iterator iter = container.find(key);
    return iter!=container.end();
}

Uwaga: nie jest to prawdziwa funkcja, której używam, ale po prostu coś głupiego, co pokazuje problem.

Author: Gorgor, 2009-03-13

5 answers

Nazwa typu jest wymagana przez standard. Kompilacja szablonu wymaga dwustopniowej weryfikacji. Podczas pierwszego przejścia kompilator musi zweryfikować składnię szablonu bez podawania podstawień typu. W tym kroku zakłada się, że std::map::iterator jest wartością. Jeśli oznacza typ, wymagane jest słowo kluczowe typename.

Dlaczego jest to konieczne? Przed zastąpieniem rzeczywistych typów klucza i wartości kompilator nie może zagwarantować, że szablon nie jest specjalistyczny i że specjalizacja nie definiuje na nowo słowa kluczowegoiterator jako czegoś innego.

Możesz to sprawdzić za pomocą tego kodu:

class X {};
template <typename T>
struct Test
{
   typedef T value;
};
template <>
struct Test<X>
{
   static int value;
};
int Test<X>::value = 0;
template <typename T>
void f( T const & )
{
   Test<T>::value; // during first pass, Test<T>::value is interpreted as a value
}
int main()
{
  f( 5 );  // compilation error
  X x; f( x ); // compiles fine f: Test<T>::value is an integer
}

Ostatnie wywołanie nie powiedzie się z błędem wskazującym, że podczas pierwszego etapu kompilacji szablonu f() test::wartość została zinterpretowana jako wartość, ale instancja szablonu Testz typem X daje Typ.

 54
Author: David Rodríguez - dribeas,
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
2009-11-25 23:48:18

Cóż, GCC właściwie nie wymaga typedef -- typename wystarczy. To działa:

#include <iostream>
#include <map>

template<typename KEY, typename VALUE>
bool find(const std::map<KEY,VALUE>& container, const KEY& key)
{
    typename std::map<KEY,VALUE>::const_iterator iter = container.find(key);
    return iter!=container.end();
}

int main() {
    std::map<int, int> m;
    m[5] = 10;
    std::cout << find(m, 5) << std::endl;
    std::cout << find(m, 6) << std::endl;
    return 0;
}

Jest to przykład problemu parsowania kontekstowego. To, co oznacza dana linia, nie wynika tylko ze składni w tej funkcji - musisz wiedzieć, czy std::map<KEY,VALUE>::const_iterator jest typem, czy nie.

Nie mogę wymyślić przykładu czego ...::const_iterator może być z wyjątkiem typu, który również nie byłby błędem. Więc myślę, że kompilator może się dowiedzieć, że ma być typem, ale może to być trudne dla słabego kompilatora (pisarzy).

Norma wymaga użycia typename tutaj, zgodnie z LITB w sekcji 14.6 / 3 normy.

 31
Author: Magnus Hoff,
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
2009-03-13 13:23:26

Wygląda na to, że VS / ICC dostarcza typename słowa kluczowego tam, gdzie uważa, że jest to wymagane. Zauważ, że jest to zła rzecz (TM) - pozwolić kompilatorowi zdecydować, czego ty chcesz. To dodatkowo komplikuje problem, wpajając zły nawyk pomijania typename, gdy jest to wymagane i jest koszmarem przenośności. To zdecydowanie nie jest standardowe zachowanie. Spróbuj w trybie strict standard lub Comeau.

 4
Author: dirkgently,
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
2009-03-13 11:37:46

Jest to błąd w kompilatorze Microsoft C++ - w twoim przykładzie std::map::iterator może nie być typem (możesz mieć wyspecjalizowaną std:: map na kluczu, wartość tak, aby std::map::iterator był zmienną na przykład).

GCC zmusza cię do napisania poprawnego kodu (nawet jeśli to, co miałeś na myśli, było oczywiste), podczas gdy kompilator Microsoftu poprawnie domyśla się, co miałeś na myśli (nawet jeśli kod, który napisałeś, był nieprawidłowy).

 3
Author: Joe Gauterin,
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
2009-03-13 12:11:10

Należy zauważyć, że problem wartości / typu kinding nie jest podstawowym problemem. Głównym problemem jest parsowanie . Consider

template<class T>
void f() { (T::x)(1); }

Nie ma sposobu, aby stwierdzić, czy jest to cast lub wywołanie funkcji, chyba że słowo kluczowe typename jest obowiązkowe. W takim przypadku powyższy kod zawiera wywołanie funkcji. Ogólnie rzecz biorąc, wybór nie może być opóźniony bez całkowitego rezygnacji z parsowania, po prostu rozważ fragment

(a)(b)(c)

Jeśli nie pamiętasz, Obsada ma wyższy priorytet niż wywołanie funkcji w C, jeden z powodów, dla których Bjarne chciał funkcji styl rzuca. Dlatego nie można stwierdzić, czy powyższe oznacza

(a)(b)  (c)   // a is a typename

Lub

(a) (b)(c)    // a is not a typename , b is

Lub

(a)(b) (c)    // neither a nor b is a typename

Gdzie wstawiłem spację, aby wskazać grupowanie.

Uwaga również słowo kluczowe " templatename "jest wymagane z tego samego powodu co" typename", nie możesz analizować rzeczy bez znajomości ich rodzaju w C/C++.

 2
Author: Yttrill,
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
2010-11-30 17:25:57