Que sont les modèles de guides de déduction et quand devons-nous les utiliser?

87

La norme C ++ 17 introduit des "guides de déduction de modèles". Je suppose qu'ils ont quelque chose à voir avec la nouvelle déduction d'arguments de modèle pour les constructeurs introduite dans cette version de la norme, mais je n'ai pas encore vu une explication simple, de style FAQ, de ce qu'ils sont et à quoi ils servent.

  • Que sont les guides de déduction de modèles dans C ++ 17?

  • Pourquoi (et quand) en avons-nous besoin?

  • Comment les déclarer?

Tristan Brindle
la source
En particulier, je serais intéressé de savoir si des guides de déduction sont réellement fournis par le C ++ 17 STL (par exemple pour std :: pair ou std :: tuple). Quelle est la liste complète des types de modèles standard "déductibles" à partir de C ++ 17?
Quuxplusone
Je serais intéressé de savoir si un compilateur prend en charge cela. J'ai essayé gcc, clang et vc ++. rextester.com/DHPHC32332 Nevermind, j'ai trouvé que cela fonctionne uniquement avec gc ++ 8.1 C ++ 17 et 2a g ++ -std = c ++ 17 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Jean-Simon Brochu

Réponses:

98

Les guides de déduction de modèle sont des modèles associés à une classe de modèle qui indiquent au compilateur comment traduire un ensemble d'arguments de constructeur (et leurs types) en paramètres de modèle pour la classe.

L'exemple le plus simple est celui de std::vectoret son constructeur qui prend une paire d'itérateurs.

template<typename Iterator>
void func(Iterator first, Iterator last)
{
  vector v(first, last);
}

Le compilateur a besoin de comprendre ce que vector<T>de » Ttype sera. Nous savons quelle est la réponse; Tdevrait être typename std::iterator_traits<Iterator>::value_type. Mais comment dire au compilateur sans avoir à taper vector<typename std::iterator_traits<Iterator>::value_type>?

Vous utilisez un guide de déduction:

template<typename Iterator> vector(Iterator b, Iterator e) -> 
    vector<typename std::iterator_traits<Iterator>::value_type>;

Cela indique au compilateur que, lorsque vous appelez un vectorconstructeur correspondant à ce modèle, il déduit la vectorspécialisation en utilisant le code à droite de ->.

Vous avez besoin de guides lorsque la déduction du type des arguments n'est pas basée sur le type de l'un de ces arguments. L'initialisation d'un à vectorpartir d'un initializer_listutilise explicitement les vector's T, donc il n'a pas besoin d'un guide.

Le côté gauche ne spécifie pas nécessairement un constructeur réel. La façon dont cela fonctionne est que, si vous utilisez la déduction de constructeur de modèle sur un type, cela correspond aux arguments que vous passez à tous les guides de déduction (les constructeurs réels du modèle principal fournissent des guides implicites). S'il existe une correspondance, il l'utilise pour déterminer les arguments de modèle à fournir au type.

Mais une fois que cette déduction est faite, une fois que le compilateur a déterminé les paramètres du modèle pour le type, l'initialisation de l'objet de ce type se déroule comme si rien de tout cela ne s'était produit. Autrement dit, le guide de déduction sélectionné ne doit pas nécessairement correspondre au constructeur sélectionné.

Cela signifie également que vous pouvez utiliser des guides avec des agrégats et une initialisation d'agrégats:

template<typename T>
struct Thingy
{
  T t;
};

Thingy(const char *) -> Thingy<std::string>;

Thingy thing{"A String"}; //thing.t is a `std::string`.

Les guides de déduction ne sont donc utilisés que pour déterminer le type en cours d'initialisation. Le processus réel d'initialisation fonctionne exactement comme avant, une fois que cette détermination a été faite.

Nicol Bolas
la source
7
Hmm, il m'est venu à l'esprit que même avec le guide, vector v{first, last};je ne ferais pas la bonne chose :(
TC
3
@TC… sauf si la bonne chose est de créer un vecteur d'itérateurs. Et std::string{32,'*'}[0] == ' '(pour ASCII). Mais tout cela est vrai depuis C ++ 11.
Arne Vogel
2
que se passe-t-il avec le paramètre de vecteur d'allocateur? que se passerait-il si le paramètre de vecteur d'allocateur n'avait pas d'argument par défaut? (vous ne pouvez pas le déduire de InputIterator)
gnzlbg
@NicolBolas: Pourriez-vous expliquer en détail comment les guides de déduction implicites et explicites peuvent fonctionner dans le contexte de classes partiellement ou entièrement spécialisées (dont les constructeurs n'ont clairement pas besoin d'avoir des types de paramètres correspondant à ceux du modèle principal)? Il est difficile de trouver des informations à ce sujet grâce à une recherche rapide.
user541686
1
@NicolBolas: Je vois. Il n'est pas clair pour moi que la question porte du tout sur les guides de déduction explicites ... Je pense qu'il est utile d'inclure simplement ce que vous avez littéralement écrit dans ce commentaire.
user541686