4

Je regardais cette question trouve ici Template function overload for type containing a typeFonction Modèle de surcharge Résolution et Optimisations du compilateur

Lorsque l'OP user2079802 fourni ce code pour son/sa question:

Je suis en train de faire ce qui suit :

#include <iostream> 
#include <vector> 
#include <tuple> 

template <typename T> 
void f(T t) { 
    std::cout << "1" << std::endl; 
} 

template <typename T, typename V> 
void f(T<std::tuple<V>> t) { 
    std::cout << "2" << std::endl; 
} 

int main() { 
    f(std::list<double>{}); // should use first template 
    f(std::vector<std::tuple<int>>{}); // should use second template 
} 

Quelle est la manière la plus simple de faire cela en C++ 14? Je pensais que je pourrais trier des motifs de cette façon, mais le compilateur ne l'aura pas.

Et songyuanyao fourni cette réponse:

Le paramètre modèle T est utilisé comme modèle nom, il devrait donc être déclarée comme template template parameter. par exemple.

template <template <typename...> class T, typename V> 
//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
void f(T<std::tuple<V>> t) { 
    std::cout << "2" << std::endl; 
} 

LIVE


La réponse qui a été fournie a effectivement corriger les erreurs de compilation et le code ne fonctionne correctement. Je pose une question sur cet extrait de code pour plus de clarté. L'OP essayait à l'origine de modéliser les types de gabarit mais avait une syntaxe incorrecte pour les paramètres de gabarit de gabarit. Quand je courais la réponse dans mon IDE, compilateur & Debugger {MSVS 2017 CE} en cours d'exécution sur un 64bit Intel machine Windows 7 J'arrive de remarquer que, dans la fonction de l'OP appelle dans leur fonction principale:

f(std::list<double>{}); 
f(std::vector<std::tuple<int>>{}); 

Que l'appel de la 2ème fonction appelle en fait le 1er modèle de fonction et non le 2ème. Cela soulève quelques questions:

  • Est-ce que cela se produit en raison des optimisations du compilateur?
  • Est-ce le résultat d'une résolution de surcharge?
  • Que se passe-t-il réellement sous le capot du compilateur quand choisit d'utiliser le premier modèle de fonction sur le 2ème?
  • Ou est-ce un bug avec le compilateur MSVC?
+0

Eh, obtenez-vous la sortie "1 2"? Ou en tirez-vous cette conclusion "l'appel de 2ème fonction appelle en fait le 1er modèle de fonction" de ce que vous voyez dans le débogueur? –

+0

@DanielJour Je reçois une valeur imprimée de '1' au lieu de' 2', donc elle appelle la 1ère fonction et non la 2ème. –

+2

C'est un bogue dans le compilateur MSVC. –

Répondre

2

Ce n'est pas un bogue dans le compilateur MSVC. C'est vraiment le résultat d'une ambiguïté dans la norme concernant les paramètres de template par défaut.

Vous voyez, std::vector a en réalité 2 arguments de modèle: le type et un allocateur.

Si vous refactorisons la réponse de cette question pour tenir compte de l'allocateur

template <typename T> 
void f(T t) { 
    std::cout << "1" << std::endl; 
} 

template <template <typename...> class T, typename V> 
void f(T<std::tuple<V>, std::allocator<std::tuple<V>>> t) { 
    std::cout << "2" << std::endl; 
} 

Il fonctionnera correctement dans tous les compilateurs: msvc demo, gcc demo, clang demo.

Here's the original defect report (CWG 150)

P0522R0 a la dernière discussion de Novembre 2016, où ils proposent que le type de modèle partiel correspondant vous faites référence dans la réponse de songyuanyao sera correcte selon la norme.

Les changements proposés dans P0522R0 sont incorporés dans la norme C++ 17 (le projet N4296 était celui que j'ai vérifié). Jusqu'à ce que la norme soit finalisée et MSVC prétend avoir le support complet de C++ 17, je ne l'appellerais pas un bogue dans le compilateur. Pour l'instant, ils reconnaissent que cette proposition spécifique n'a pas encore été incorporée dans leur compilateur à partir de VS 2017.3 [P2] (source)

+0

Cela ressemble à un problème légèrement différent. L'exemple dans le rapport est rejeté par les trois principaux compilateurs tandis que le code OP fonctionne comme prévu avec g ++ et clang ++. Votre solution proposée manque le point. La raison d'utiliser un pack de paramètres est que nous ne voulons pas savoir ou nous intéresser aux autres paramètres du template. Votre solution force le programmeur à savoir que 'T' accepte deux arguments, le second étant' std :: allocator <...> '(nous pourrions écrire 'template classe T' qui fonctionne même en C++ 03). Heureusement, il est facile de [corriger] (https://pastebin.com/FmKfgqQY). –

+0

@ n.m. L'utilisation explicite de 'std :: allocator' était à des fins de démonstration :-). Comme il s'agit d'une question différente de celle du rapport, je suis enclin à exprimer (respectueusement) mon désaccord. Le code OP ne fonctionne pas comme prévu dans gcc avec l'option C++ 14 [demo] (https://wandbox.org/permlink/RTRvJJAicYDUkuND), alors qu'il fonctionne correctement avec l'option C++ 17 [demo] (https : //wandbox.org/permlink/x0w1SsMvr0s1pDA1) – AndyG

+0

donc le comportement a changé entre gcc 6 et 7 (j'ai seulement vérifié gcc 6). –