Pourquoi l’argument de modèle ne peut-il être déduit lorsqu’il est utilisé comme paramètre de modèle pour un autre modèle?

Qu’est-ce qui ne va pas dans ce code?

#include  template struct TMap { typedef std::map Type; }; template T test(typename TMap ::Type &tmap_) { return 0.0; } int _tmain(int argc, _TCHAR* argv[]) { TMap::Type tmap; tmap[1.1] = 5.2; double d = test(tmap); //Error: could not deduce template argument for T return 0; } 

    C’est un contexte non déductible. C’est pourquoi l’argument de modèle ne peut pas être déduit par le compilateur.

    Imaginez si vous pouviez avoir TMap spécialisé comme suit:

     template <> struct TMap { typedef std::map  Type; }; 

    Comment le compilateur déduirait le type SomeType , étant donné que TMap::Type est std::map ? Ça ne peut pas. Il n’est pas garanti que le type que vous utilisez dans std::map soit aussi le type dans TMap . Le compilateur ne peut pas faire cette hypothèse dangereuse. Il ne peut y avoir aucune relation entre les arguments de type , que ce soit.

    Vous pouvez également avoir une autre spécialisation de TMap définie comme suit:

     template <> struct TMap { typedef std::map  Type; }; 

    Cela rend la situation encore pire. Maintenant vous avez le suivant:

    • TMap::Type = std::map .
    • TMap::Type = std::map .

    Maintenant, demandez-vous: donné TMap::Type est std::map , comment le compilateur pourrait-il savoir si T est SomeType ou OtherType ? Il ne peut même pas savoir combien de choix il a, il ne peut pas non plus connaître les choix eux-mêmes …

    Je vous demande simplement de faire des expériences de pensée (en supposant qu’il puisse connaître l’ensemble des choix ).

    Exactement ce que dit le message d’erreur du compilateur: dans TMap::Type , T n’est pas déductible selon la norme. La raison en est probablement qu’il n’est pas techniquement possible de l’implémenter: le compilateur devrait instancier tous les TMap possibles TMap pour voir si un (et un seul) correspondait au type que vous avez passé. Et il y a un nombre infini de TMap .

    Même vous avez:

     TMap::Type = std::map. 

    Mais avant d’appeler test (tmap)

     TMap::Type tmap; tmap[1.1] = 5.2; double d = test(tmap); 

    Vous l’avez déjà déclaré comme

     TMap::Type tmap; 

    pourquoi cette information ne peut pas être utilisée. #typedef n’est pas un simple remplacement de chaîne.

    Je ne pense pas que “nous ne pouvons pas faire cela” argument est correct. Si nous modifions légèrement cet exemple, le compilateur déduit volontiers des arguments pour nous.

     template struct TMap //... template  struct tmap_t : TMap::Type {}; template T test(tmap_t tmap) // ... tmap_t tmap; // ... double d = test(tmap); // comstacks just fine. 

    Je ne vois pas de différence énorme entre l’exemple original et le mien. Le vrai problème ici semble être que C ++ traite les typedefs et les déclarations de type différemment

    Est-ce une bonne chose?