Por que não é necessário usar o typename para tipos dependentes no seguinte caso?

10

Eu tenho lido sobre como remover a referência de um tipo aqui .

Dá o seguinte exemplo:

#include <iostream> // std::cout
#include <type_traits> // std::is_same

template<class T1, class T2>
void print_is_same() {
  std::cout << std::is_same<T1, T2>() << '\n';
}

int main() {
  std::cout << std::boolalpha;

  print_is_same<int, int>();
  print_is_same<int, int &>();
  print_is_same<int, int &&>();

  print_is_same<int, std::remove_reference<int>::type>(); // Why not typename std::remove_reference<int>::type ?
  print_is_same<int, std::remove_reference<int &>::type>();// Why not typename std::remove_reference<int &>::type ?
  print_is_same<int, std::remove_reference<int &&>::type>();// Why not typename std::remove_reference<int &&>::type ?
}

Os types nos std::remove_referencetraços são tipos dependentes.

Possível implementação

template< class T > struct remove_reference      {typedef T type;};
template< class T > struct remove_reference<T&>  {typedef T type;};
template< class T > struct remove_reference<T&&> {typedef T type;};

Mas por que não usa typename std::remove_reference</*TYPE*/>::type?

LernerCpp
fonte

Respostas:

22

Os types nos std::remove_referencetraços são tipos dependentes.

Não, eles não são nomes dependentes aqui. Os argumentos do modelo foram especificados explicitamente como int, int&e int&&. Portanto, os tipos são conhecidos neste momento.

Por outro lado, se você usar std::remove_referencecom um parâmetro de modelo, por exemplo,

template <typename T>
void foo() {
    print_is_same<int, typename std::remove_reference<T>::type>();
}

você precisará usar typenamepara dizer que esse std::remove_reference<T>::typeé um tipo, pois sua expressão agora depende do parâmetro do modelo T.

songyuanyao
fonte
5

Em poucas palavras, você precisa typenamegarantir que o compilador

std::remove_reference<int>::type

realmente é um tipo. Vamos considerar outro modelo

template <typename T>
struct foo {
    using type = int;
};

Aqui foo::typeestá um tipo. Mas e se alguém fornecer uma especialização ao longo da linha de

template <> struct foo<int> {
    int type;
};

Agora typenão é um tipo, mas um int. Agora, quando você usa foo dentro de um modelo:

template <typanem T> 
struct bar {
    using type = typename foo<T>::type;
};

Você precisa garantir que o compilador foo<T>::typerealmente seja um tipo, e não outra coisa, porque apenas olhando bar(e o modelo principal foo) o compilador não pode saber disso.

No entanto, em sua maina std::remove_reference<int>::typenão depende de um parâmetro de modelo, portanto, o compilador pode facilmente verificar se ele é um tipo.

idclev 463035818
fonte
0

A palavra-chave typename é usada para ajudar o compilador a analisar a fonte. Aponta que o ID é um nome de tipo, não um nome de variável ou nome de método. Mas em situações como acima, o compilador pode descobrir por si próprio, portanto, essa palavra-chave não é necessária.

Sergey Strukov
fonte