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 :
Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
auto concept LessThanComparable<typename T> {
    bool operator<(T, T);
}
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.

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 :
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    template <class T> void f(T);
    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(enable_if_t<my_trait_v<T>, 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> auto f(T) -> enable_if_t<my_trait_v<T>, void>;
    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, typename = enable_if_t<my_trait_v<T>>> void f(T);
    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 :
  • 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 :
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    template <class T> void f(T, decltype(declval<T>().f())* = 0);
    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
    1
    2
    template <class T> void f(T) requires requires (T t) {t.f();};
          template <class T> void f(T);
    Les surcharges sont mutuellement exclusives.
  • 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 :
  • la proposition définit une nouvelle syntaxe pour déclarer des templates respectant une contrainte :
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    C{A,B} void f(A a, B b);
    toutefois, cette syntaxe n’est pas appréciée ;
  • 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