La spécification du C++17 n'intègrera pas les concepts
Découvrez les raisons logiques et techniques de son absence
La nouvelle spécification du C++, nommée C++17 approche à grands pas. Toutefois, la fonctionnalité des concepts n'intègrera pas la future spécification. Tom Honermann explique sur son blog les raisons faisant que c'était improbable, voire impossible.
Toutefois, avant de décrire ces raisons, rappelons ce que sont les concepts.
Prenons le concept suivant :
Celui-ci indique que n’importe quel type ayant un operator< et qui prend en paramètre deux objets et retournant un booléen sera considéré comme un LessThanComparable. Ensuite, il est possible d’utiliser le concept pour restreindre les types pouvant être passés à un template.
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 auto concept LessThanComparable<typename T> { bool operator<(T, T); }
Le but des concepts est d'apporter une solution à un manque du C++. En effet, même s'il est possible de contourner le manque, il est impossible d'apporter une solution propre. Grâce aux concepts il devient possible :
- de contraindre les arguments d'une fonction sans pour autant désactiver la déduction de ceux-ci et sans gêner la meta arity des fonctions templates ainsi contraintes. Prenons l’exemple suivant :
L’exemple est plutôt simple. Toutefois, nous aimerions ajouter une interface. Pour ce faire, nous voudrions contraindre les paramètres de la fonction :
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part template <class T> void f(T);
Mais ce faisant, nous avons perdu la déduction des arguments. Aussi, cela ne fonctionnera pas pour les constructeurs templates. Une seconde approche serait :
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part template <class T> void f(enable_if_t<my_trait_v<T>, T>);
La contrainte du paramètre se situe dans le type de retour. Toutefois, cela ne marche toujours pas pour les constructeurs templates. Ce que nous pouvons corriger en ajoutant une contrainte sur l’argument template :
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part template <class T> auto f(T) -> enable_if_t<my_trait_v<T>, void>;
Malheureusement, la meta arity est passée de 1 à 2. De plus, ce n’était que des contournements alors qu’avec les concepts nous pourrions faire :
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part template <class T, typename = enable_if_t<my_trait_v<T>>> void f(T);
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part void f(MyConcept);- d’écrire plus facilement des surcharges tout en ayant des contraintes exclusives mutuellement. Il est souvent souhaité de pouvoir utiliser telle ou telle surcharge suivant certaines conditions sur les templates. Pour réussir, on pourrait écrire :
Ce code est dangereux. On peut facilement en arriver à ce point si on ne souhaite pas créer de trait (car c’est l’unique utilisation). De plus, les références ne sont pas gérées, la contrainte peut être ignorée en passant deux arguments à la fonction. Avec les concepts, nous pourrions écrire :
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part template <class T> void f(T, decltype(declval<T>().f())* = 0);
Les surcharges sont mutuellement exclusives.
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 template <class T> void f(T) requires requires (T t) {t.f();}; template <class T> void f(T);- d’écrire des contraintes aussi originales que nécessaires.
Malgré tout l’intérêt que peuvent avoir les concepts, ceux-ci n'intégreront pas le prochain standard. En effet, plusieurs choses ne sont pas encore claires :
- la spécification des concepts a été publiée le 15 novembre 2015, laissant peu de temps pour un retour efficace et fiable ;
- la seule implémentation est dans une version non publiée de GCC ;
- l’implémentation réalisée dans GCC a été réalisée par l’auteur de la spécification. Il n’y a donc pas eu d’avis externe sur la question de l’implémentation dans GCC ou dans les autres compilateurs ;
- seuls quelques projets utilisent les concepts, mais la spécification n’a pas été assez mise à l’épreuve dans des cas réels ;
- la spécification ne fournit pas de bibliothèque de définitions de concepts. Donc il n’est pas possible de savoir si l’écriture d’une telle bibliothèque est possible.
Toutefois, même si tous ces points avaient été réglés, Tom Honermann doute de l’intégration des concepts à la spécification du langage. En effet :
- les concepts apportent une nouvelle écriture pour les templates. Toutefois, une fonction template abrégée peut être identique à une fonction non template. Le type serait le seul indicateur pour savoir si la fonction est non template ou si elle est template :
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part void f(X x) {}- la proposition définit une nouvelle syntaxe pour déclarer des templates respectant une contrainte :
toutefois, cette syntaxe n’est pas appréciée ;
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part C{A,B} void f(A a, B b);- l’utilisation d’un concept nécessite de connaître comment il a été défini (fonction ou variable). Cela apporte confusion et est source d’erreurs ;
- les concepts sont attendus pour améliorer les messages d’erreur. Toutefois, l’utilisation erronée des concepts peut apporter des erreurs encore plus denses qu’à l’accoutumée liées à la surcharge des fonctions ;
- de nombreuses autres questions ont été soulevées et ne pourront être répondues qu’à travers des tentatives d’utilisation.
Même si ce constat est malheureux pour tout utilisateur du langage souhaitant les concepts au plus tôt, ces derniers devraient arriver dans la prochaine spécification. De plus, il y a de grandes chances pour que chaque compilateur propose une implémentation bien avant la complétion du futur standard. Finalement, ce retard permet d’affiner l’implémentation et ainsi, au comité de proposer une meilleure fonctionnalité.
Votre opinion
Aviez-vous déjà imaginé des cas d’utilisation pour les concepts ? Quels sont-ils ?
Quelles autres fonctionnalités du C++ attendez-vous ?
Source
Blog de Tom Honermann
IsoCPP
Partager