web-dev-qa-db-fra.com

Que sont les guides de déduction de gabarit et quand devrions-nous les utiliser?

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

  • Que sont les guides de déduction de gabarit en C++ 17?

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

  • Comment puis-je les déclarer?

76
Tristan Brindle

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 de paramètres (et leurs types) en arguments de modèle.

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

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

Le compilateur doit comprendre ce que vector<T> _ T type sera. Nous savons quelle est la réponse. T devrait ê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 constructeur vector correspondant à ce modèle, il en déduira la spécialisation vector à l'aide du code situé à droite de ->.

Vous avez besoin de guides lorsque la déduction du type à partir des arguments n'est pas basée sur le type de l'un de ces arguments. Initialiser un vector à partir d'un initializer_list utilise explicitement le vector de T, il n'a donc pas besoin de guide.

Le côté gauche ne spécifie pas nécessairement un constructeur. Si vous utilisez la déduction de constructeur de modèle sur un type, cela correspond aux arguments que vous transmettez à 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 cette déduction effectuée, une fois que le compilateur a déterminé les paramètres de modèle pour le type, l'initialisation de l'objet de ce type se déroule comme si rien ne s'était passé. C'est-à-dire que 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 leur initialisation:

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 d’initialisation proprement dit fonctionne exactement comme il le faisait auparavant, une fois cette détermination effectuée.

88
Nicol Bolas