La question principale fait référence aux décisions de conception dans la norme C++ qui a introduit des modèles vers 1990.
Pourquoi les concepteurs ont-ils utilisé <>
(équerres) au lieu de, disons, ()
(parenthèses rondes)? Cela aurait sauvé beaucoup de programmeurs de l'erreur liée au décalage de bits
std::vector<std::vector<int>> // does not work until C++11
qui n'a été corrigé qu'en C++ 11. Je ne vois pas la justification de l'introduction d'une syntaxe supplémentaire comme celle-là alors que, sans doute, les crochets auraient servi le même objectif tout en gardant les changements minimalistes. Vous avez pu utiliser
template(typename T) // Define template if round brackets could be used
mytemplate { ... }
...
...
mytemplate(mytemplate(int)) obj; //Instantiate template when round brackets could be used
Quelqu'un qui connaît bien l'histoire du C++ peut-il trouver la justification de la conception originale de l'utilisation des équerres? Sinon, pouvez-vous montrer pourquoi d'autres solutions n'auraient pas fonctionné aussi bien?
Des modèles ont été introduits dans l'article USENIX de 1988 Types paramétrés pour C++ par Bjarne Stroustrup, incorporé plus tard dans Le manuel de référence annoté C++ publié en 1990 (la version avant C++ standardisée). Selon le journal,
Les crochets
<…>
Sont utilisés de préférence aux parenthèses(…)
En partie pour souligner la nature différente des arguments du modèle (ils sera évalué au moment de la compilation) et en partie parce que les parenthèses sont déjà désespérément surutilisées en C++ .…
9.2.
<…>
Vs(…)
Mais pourquoi utiliser des crochets au lieu de parenthèses? Comme mentionné précédemment, les parenthèses ont déjà de nombreuses utilisations en C++. Un indice syntaxique (les crochets
<…>
) Peut être utile pour rappeler à l'utilisateur la nature différente des paramètres de type (ils sont évalués au moment de la compilation) . De plus, l'utilisation de parenthèses pourrait conduire à un code assez obscur:template(int sz = 20) class buffer { buffer(int i = 10); // ... }; buffer b1(100)(200); buffer b2(100); // b2(100)(10) or b2(20)(100)? buffer b3; // legal?
Ces problèmes deviendraient une grave préoccupation pratique si la notation pour la désambiguïsation explicite des appels de fonction surchargés était adoptée. L'alternative choisie semble beaucoup plus propre:
template<int sz = 20> class buffer { buffer(sz)(int i = 10); // ... }; buffer b1<100>(200); buffer b2<100>; // b2<100>(10) buffer b3; // b3<20>(10) buffer b4(100); // b4<20>(100)
Le document explique également pourquoi les mots clés template
et class
sont utilisés.
Notez que le Stroustrup a placé le <…>
après le nom de la variable de la même manière que int x[10]
Pour argumenter contre (…)
, Bien que ce placement soit jamais utilisé ailleurs dans le journal.
Son argument selon lequel "l'utilisation de (…)
Peut conduire à un code obscur/ambigu" est toujours valable. Comme mentionné dans le commentaire de cette question, l'utilisation de parenthèses T(x)
conduit à une ambiguïté avec le type de fonction ou l'appel de fonction (notez que T
peut être un modèle de fonction et que les valeurs C++ peuvent être des arguments de modèle).
De même, l'utilisation de crochets T[x]
Conduit à une ambiguïté avec le type de tableau ou l'indexation.
Je ne vois pas pourquoi T{x}
Ne peut pas encore être utilisé, peut-être qu'il n'a tout simplement pas été pris en compte, ou peut-être qu'il est trop laid d'avoir {…}
Utilisé partout.