Pourquoi les modèles C ++ utilisent-ils la syntaxe entre crochets?

La question principale concerne les décisions de conception de la norme C ++ qui ont introduit les modèles vers 1990.

Pourquoi les concepteurs ont-ils utilisé (crochets angulars) au lieu de, par exemple, () (parenthèses rondes)? Cela aurait sauvé beaucoup de programmeurs de l’erreur liée au décalage de bit

 std::vector<std::vector> // does not work until C++11 

cela n’a été corrigé que dans C ++ 11. Je ne vois pas la raison d’introduire une syntaxe supplémentaire comme celle-ci lorsque, sans doute, les parenthèses auraient servi le même objective tout en gardant les changements minimalistes. Insted vous auriez 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 

Est-ce que quelqu’un qui connaît bien l’histoire du C ++ peut trouver la raison d’être de l’utilisation des crochets? Sinon, pouvez-vous montrer pourquoi d’autres solutions n’auraient pas fonctionné aussi bien?

Des modèles ont été introduits dans le document USENIX 1988 sur les types paramétrés pour C ++ par Bjarne Stroustrup, puis incorporés dans le Manuel de référence C ++ annoté publié en 1990 (la version avant le standard C ++). Selon le journal,

Les parenthèses <…> sont utilisées de préférence aux parenthèses (…) partie pour souligner la nature différente des arguments de modèle (ils seront évalués au moment de la compilation) et en partie parce que les parenthèses sont déjà désespérément surexploitées en C ++ .

9.2. <…> Vs (…)

Mais pourquoi utiliser des parenthèses 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 parenthèses <…> ) peut servir à rappeler à l’utilisateur la nature différente des parameters 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 préoccupation pratique sérieuse si la notation de la désambiguïsation explicite des appels de fonctions surchargés était adoptée. L’alternative choisie semble beaucoup plus propre:

 template 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 papier explique également pourquoi les mots-clés de template et de 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 contester (…) , bien que cet emplacement ne soit jamais utilisé ailleurs dans le papier.

Son argument selon lequel “utiliser (…) peut conduire à un code obscur / ambigu” rest cependant valable. Comme mentionné dans le commentaire de cette question, l’utilisation de la parenthèse T(x) entraîne 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 ++ sont des arguments de modèle).

De même, l’utilisation des 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 que cela n’a tout simplement pas été pris en compte, ou peut-être que c’est trop laid d’avoir {…} utilisé partout.