J'ai lu sur la suppression de la référence d'un type, ici .
Il donne l'exemple suivant:
#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 ?
}
Les type
s dans le std::remove_reference
les traits sont des types dépendants.
Implémentation possible
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;};
Mais pourquoi n'utilise-t-il pas typename std::remove_reference</*TYPE*/>::type
?
Les
type
s dans lestd::remove_reference
les traits sont des types dépendants.
Non, ils ne sont pas noms dépendants ici. Les arguments du modèle ont été spécifiés explicitement comme int
, int&
et int&&
. Par conséquent, les types sont connus à ce stade.
En revanche, si vous utilisez std::remove_reference
avec un paramètre de modèle, par exemple.
template <typename T>
void foo() {
print_is_same<int, typename std::remove_reference<T>::type>();
}
alors vous devez utiliser typename
pour dire que std::remove_reference<T>::type
est un type car votre expression dépend maintenant du paramètre de modèle T
.
En un mot, vous avez besoin de typename
pour vous assurer que le compilateur
std::remove_reference<int>::type
est vraiment un type. Considérons un autre modèle
template <typename T>
struct foo {
using type = int;
};
Ici foo::type
est un type. Mais que se passe-t-il si quelqu'un propose une spécialisation
template <> struct foo<int> {
int type;
};
Maintenant, type
n'est pas un type mais un int
. Maintenant, lorsque vous utilisez foo dans un modèle:
template <typanem T>
struct bar {
using type = typename foo<T>::type;
};
Vous devez vous assurer que le compilateur foo<T>::type
est vraiment un type, pas autre chose, car en ne regardant que bar
(et le modèle primaire foo
) le compilateur ne peut pas le savoir.
Cependant, dans votre main
le std::remove_reference<int>::type
ne dépend pas d'un paramètre de modèle, donc le compilateur peut facilement vérifier s'il s'agit d'un type.
Le mot-clé typename est utilisé pour aider le compilateur à analyser la source. Il indique que l'ID est un nom de type, pas un nom de variable ou un nom de méthode. Mais dans des situations comme ci-dessus, le compilateur peut le comprendre lui-même, donc ce mot-clé n'est pas requis.