Quando a palavra-chave “typename” é necessária?

Duplicar Possível:
Oficialmente, para que é o typename?
Onde e por que devo colocar as palavras-chave template e typename?

considere o código abaixo:

template class C { struct P {}; vector

vec; void f(); }; template void C::f() { typename vector

::iterator p = vec.begin(); }

Por que a palavra-chave “typename” é necessária neste exemplo? Existem outros casos em que “typename” deve ser especificado?

    Resposta curta: Sempre que se referir a um nome nested que seja um nome dependente , isto é, nested dentro de uma instância de gabarito com um parâmetro desconhecido.

    Resposta longa: Existem três camadas de entidades em C ++: valores, tipos e modelos. Todos esses podem ter nomes, e o nome por si só não informa qual camada de entidade é. Em vez disso, as informações sobre a natureza da entidade de um nome devem ser inferidas do contexto.

    Sempre que essa inferência é impossível, você precisa especificá-lo:

     template  struct Magic; // defined somewhere else template  struct A { static const int value = Magic::gnarl; // assumed "value" typedef typename Magic::brugh my_type; // decreed "type" // ^^^^^^^^ void foo() { Magic::template kwpq(1, 'a', .5); // decreed "template" // ^^^^^^^^ } }; 

    Aqui os nomes Magic::gnarl , Magic::brugh e Magic::kwpq tiveram que ser explicados, porque é impossível dizer: Como Magic é um template, a própria natureza do tipo Magic depende de T – pode haver especializações que são completamente diferentes do modelo primário, por exemplo.

    O que torna Magic::gnarl um nome dependente é o fato de estarmos dentro de uma definição de template, onde T é desconhecido. Se tivéssemos usado Magic , isso seria diferente, já que o compilador sabe (você promete!) A definição completa de Magic .

    (Se você quiser testar isso você mesmo, aqui está uma definição de amostra de Magic que você pode usar. Perdoe o uso de constexpr na especialização para brevidade; se você tiver um compilador antigo, sinta-se livre para alterar a declaração de constante de membro estático para o antigo estilo pré-C ++ 11.)

     template  struct Magic { static const T gnarl; typedef T & brugh; template  static void kwpq(int, char, double) { T x; } }; template <> struct Magic { // note that `gnarl` is absent static constexpr long double brugh = 0.25; // `brugh` is now a value template  static int kwpq(int a, int b) { return a + b; } }; 

    Uso:

     int main() { A a; a.foo(); return Magic::kwpq(2, 3); // no disambiguation here! } 

    A palavra-chave typename é necessária porque o iterator é um tipo dependente em P O compilador não pode adivinhar se o iterator se refere a um valor ou a um tipo, portanto ele assume um valor a menos que você grite typename . É necessário sempre que houver um tipo dependente de um argumento de modelo, em um contexto em que os tipos ou valores sejam válidos. Por exemplo, como as classs base, typename não é necessário, pois uma class base deve ser um tipo.

    No mesmo assunto, há uma palavra-chave de template usada para informar ao compilador que algum nome dependente é uma function de modelo em vez de um valor.

    A palavra-chave typename é necessária sempre que um nome de tipo depende de um parâmetro de modelo (portanto, o compilador pode ‘conhecer’ a semântica de um identificador ( tipo ou valor ) sem ter uma tabela de símbolos completa na primeira passagem).


    Não no mesmo significado e um pouco menos comum, a palavra-chave typename solitária também pode ser útil ao usar parâmetros de modelo genéricos: http://ideone.com/amImX

     #include  #include  #include  template