Chaque jour de décembre a droit à sa surprise. Après la fixation de l’ordre d’évaluation des expressions, aujourd’hui, le calendrier de l’Avent du C++ présente la spécification technique P0292 concernant les conditions à la compilation, grâce à if constexpr
.
Sommaire
- Plusieurs nommages
- Simplification du code générique
- Remplacement du SFINAE
- Mixer
if constexpr
etif
classique - Remplacement du
#if
? - Faut‐il continuer à apprendre le C++ ?
- Réutilisation
- Les auteurs
- Continuer à améliorer ce document
- La suite
Plusieurs nommages
Cette fonctionnalité a connu plusieurs nommages au fil des discussions entre les membres du comité de standardisation :
-
2011 : le nommage original était
static_if
etstatic_else
; -
2015 : l’avènement du mot‐clef
constexpr
apporte une nouvelle terminologie qui se différencie destatic
. Le nommage devientconstexpr_if
etconstexpr_else
; -
mars 2016 : lors de la première réunion du comité de normalisation, les deux mots ont été détachés pour donner
constexpr if
, etconstexpr_else
devient justeelse
. -
juin 2016 : à la seconde réunion, les deux mots sont inversés pour donner
if constexpr
.
Simplification du code générique
Cette fonctionnalité est un outil puissant pour écrire du code générique compact. On combine plusieurs patrons (templates).
Sans if constexpr
:
void fonction()
{ std::cout << std::endl; }
template <class T>
void fonction (const T& t)
{ std::cout << t; }
template <class T, class... R>
void fonction (const T& t, const R&... r)
{
fonction(t); // Gère un argument
fonction(r...); // Gère le reste
}
Avec if constexpr
:
template <class T, class... R>
void fonction (const T& t, const R&... r)
{
std::cout << t; // Gère un argument
if constexpr (sizeof...(r))
fonction(r...); // Gère le reste
else
std::cout << std::endl;
}
Remplacement du SFINAE
Brève explication sur le SFINAE
D’après Wikipédia en français :
Le mécanisme décrit par l’abréviation SFINAE (Substitution Failure Is Not an Error) permet de surcharger un template par plusieurs classes (ou fonctions), même si certaines spécialisations, par exemple, ne peuvent pas être utilisées pour tous les paramètres de templates. Le compilateur, lors de la substitution, ignore alors les instanciations inapplicables, au lieu d’émettre une erreur de compilation.
C’est une technique de métaprogrammation qui permet de sélectionner une fonction générique surchargée à la compilation. Plus spécifiquement, le SFINAE signifie que le compilateur ne considère pas comme une erreur un problème d’instanciation. Le compilateur va alors essayer de trouver une autre instanciation similaire possible.
Voir aussi l’article sur Wikipédia en anglais ou sur cppreference.com. Un article en français, mais non libre, est également disponible sur developpez.com.
Chère lectrice, cher lecteur LinuxFr.org. Souhaite‐tu une dépêche consacrée au SFINAE ? Alors exprime‐toi dans les commentaires et de nombreuses personnes vont certainement unir leurs forces pour t’offrir un superbe article sous licence libre. Bon, si tu n’oses pas demander, personne n’aura l’impulsion pour se lancer…
Revenons au if constexpr
Dans certains cas, le if constexpr
peut avantageusement remplacer la technique du SFINAE.
Sans if constexpr
Voir sur gcc.godbolt.org.
template<class T>
auto f(T x) -> decltype(std::enable_if_t< std::is_function_v<decltype(T::f)>,int>{})
{ // ^---true si T::f existe et que c'est une fonction
return x.f();
}
template<class T>
auto f(T x) -> decltype(std::enable_if_t< ! std::is_function_v<decltype(T::f)>,int>{})
{ // ^---le contraire
return 0;
}
Trait
L’exemple précédent utilise enable_if
et is_function
qui sont des traits de la bibliothèque standard. Ce sont des classes templates
qui réalisent un petit traitement à la compilation nécessaire au SFINAE.
Par simplification, nous avons utilisé les suffixes …_t
et …_v
dans std::enable_if_t
(C++14) et std::is_function_v
(C++17) qui correspondent respectivement au type d’aide std::enable_if<…>::type
et à la variable d’aide std::is_function<…>::value
.
La bibliothèque standard de GCC 7 implémente enfin la variable d’aide …_v
(C++17). En revanche, cela ne semble pas encore être le cas pour Clang-3.8.
Avec if constexpr
Voir sur gcc.godbolt.org.
template<class T>
int f (T x)
{
if constexpr( std::is_function_v<decltype(T::f)> )
return x.f();
else
return 0;
}
Mixer if constexpr
et if
classique
Il est possible de mixer les deux syntaxes. La convention actuelle est de commencer par if constexpr
. L’inférence du type de retour peut aussi être utilisée. Un exemple vaut mieux qu’un long discours :
template <bool B>
auto f (std::string const & s)
{
if constexpr (B)
return std::string("top");
else if (s.size() > 42)
return true;
else
return false;
}
Notons que la fonction f()
n’a pas besoin d’être constexpr
pour utiliser if constexpr
, tout comme pour utiliser static_assert()
. Même les lambdas peuvent utiliser cette fonctionnalité, que du bonheur. \o/
Remplacement du #if
?
if constexpr
peut, dans certains cas, remplacer le #if
du préprocesseur, mais ce n’est pas l’objectif. Après, selon l’usage qui en sera fait…
À ce propos, qui veut se lancer dans des expérimentations ? Merci de publier vos trouvailles dans les commentaires. ;-)
Faut‐il continuer à apprendre le C++ ?
Ne pas nourrir les trolls | Ne pas nourrir les trolls |
Merci de nous aider à structurer et consolider les différentes idées sur cette question dans l’espace de rédaction collaboratif de LinuxFr.org : Faut‐il continuer à apprendre le C++ ?
Réutilisation
Le texte de cette dépêche est protégé par le droit d’auteur la gauche d’auteur et réutilisable sous licence CC BY-SA 4.0. Les images utilisées sont aussi sous licence libre (cliquer sur l’image pour plus de détails).
Donc, n’hésitez pas à réutiliser ce contenu libre pour créer, par exemple, des supports de formation, des présentations (Meetups), des publications sur d’autres blogs, des articles pour des magazines, et aussi un article C++17 sur Wikipédia dès que Wikipédia passera de la licence CC BY-SA 3.0 à la CC BY-SA 4.0 (le contenu de cette dépêche utilise la version la CC BY-SA 4.0).
Les auteurs
Par respect de la licence, merci de créditer les auteurs :
- les principaux auteurs sont Adrien Jeser et Oliver H. ;
- les nombreux autres contributeurs ayant contribué sur l’ancêtre de cette dépêche ou sur le dépôt Git sont : eggman, Yves Bourguignon, Storm, gorbal, palm123, khivapia, BAud, Segfault, Benoît Sibaud, Lucas, cracky, Martin Peres, RyDroid, olibre et Guss.
Continuer à améliorer ce document
Malgré tout le soin apporté, il reste certainement des oublis, des ambiguïtés, des fôtes… Bien que cette dépêche restera figée sur le site LinuxFr.org, il est possible de continuer à l’enrichir sur le dépôt Git du Groupe des utilisateurs C++ francophone (C++FRUG). C’est donc sur ce dépôt que se trouvent les versions les plus à jour. (ღ˘⌣˘ღ)
Alors que cet article restera figé sur le site LinuxFr.org, il continuera d’évoluer sur le dépôt Git. Merci de nous aider [à maintenir ce document à jour][md] avec vos questions/suggestions/corrections. L’idée est de partager ce contenu libre et de créer/enrichir des articles Wikipédia quand la licence sera CC BY-SA 4.0. ٩(•‿•)۶
La suite
La dépêche suivante nous dévoilera une autre nouveauté du C++17.
Chère lectrice, cher lecteur LinuxFr.org. Tu souhaites apporter ta pierre à cet édifice ? Rejoins‐nous dans l’espace de rédaction collaborative sur LinuxFr.org (un compte est nécessaire pour y accéder).
À suivre…
Aller plus loin
- Dépêche préliminaire dans « Les coulisses du standard C++ » (CC BY-SA 4.0) (123 clics)
- Dépêche de mise en bouche racontant la genèse du C++17 (CC BY-SA 4.0) (103 clics)
- Dépêche du 2 décembre : « C++17 indique la disponibilité des en‐têtes (header) » (CC BY-SA 4.0) (115 clics)
- Article sur la fonctionnalité “if constexpr” par LoopPerfect (droit d’auteur non mentionné) (115 clics)
# Nouveau langage
Posté par arnaudus . Évalué à 10.
D'abord, merci pour cette série d'articles, c'est assez agréable de pouvoir passer 5 minutes à lire quelque chose d'assez compact sur chaque nouveauté plutôt qu'une énorme dépêche ultra-résumée.
Sur le fond, quand je lis le code proposé, je me dis quand même qu'on est carrément en train de définir un nouveau langage avec la programmation générique. Je n'ai pas l'intention de résoudre en un commentaire la discussion éternelle sur le fait que C++ est ou n'est pas un langage orienté objet, mais mon point de vue est quand même que le multi-paradigme a une limite, c'est celle de la compréhension croisée entre les différents programmeurs.
Concrètement, j'ai un mal fou à discuter avec les «petits jeunes» qui apprennent la syntaxe générique du C++, parce que j'ai quand même l'impression que pour beaucoup d'applications, la programmation OO et la programmation générique permettent de faire des choses qui se superposent largement, mais qui sont assez incompatibles. On peut partir sur un design à base de templates ou sur un design à base de hiérarchies de classes, et une fois ce choix fait, on a quasiment deux dialectes incompatibles. Ça va devenir de plus en plus compliqué de définir ce qu'est le C++, puisqu'au final quelque chose comme "le logiciel est codé en C++" ne voudra plus dire grand chose, à part qu'il est compilable par un compilateur C++.
[^] # Re: Nouveau langage
Posté par Benbben . Évalué à 4.
Si je me fie à la précédente dépêche sur l'ordre d'évaluation des prédicats. L'objectif est de passer de "le logiciel est codé en C++ => c'est de la POO." à "le logiciel est codé en C++ => il est compilable par un compilateur C++ et son comportement sera le même et prévisible quelques soit le compilateur utilisé."
Ce qui me semble une bonne idée.
[^] # Re: Nouveau langage
Posté par Oliver (site web personnel) . Évalué à 5.
Oui, tout à fait.
Au début (il y a une quarantaines d'années), le C++ s’orientait exclusivement vers la Programmation Orientée Objet (POO).
Mais, depuis C++11, le C++ évolue dans d'autres directions :
static_assert
,constexpr
…) ;Et se passer aussi de la POO quand c'est possible, exemples :
Si nous regardons les nouveaux langages comme Go ou Rust, nous voyons bien que la POO n'est plus à la mode.
Je pense qu'en 2017 nous publierons de petites dépêches pour expliquer les aspects de la programmation générique et surtout la méta-programmation (et un peu de programmation fonctionnelle) car c'est l'intérêt de coder en C++. Le mot-clé
template
fait peur, démystifions-le ;-)Commentaire sous licence Creative Commons Zero CC0 1.0 Universal (Public Domain Dedication)
[^] # Re: Nouveau langage
Posté par lmg HS (site web personnel) . Évalué à 3.
Parenthèse: A.Stepanov se défend que la STL historique ait été conçue OO. Il y a diverses vidéos sur le sujet.
Dans le cas de
v.begin()
il sous-entend dans son Notes on Programming que pour passer le véto de l'intelligentzia OO qui n'avait pas encore migré vers d'autres langages à l'époque (le subjectif dans le phrasé est mien), il avait dû concéder à faire desize
& cie des fonctions membres et non des fonctions libres. Depuis le C++11 on corrige le tir. Il faut attendre C++17 pour avoirstd::size()
—même s'il est facile à écrire dès le C++11: c'est un oubli.A noter aussi les propositions autour du Uniform Call Syntax par Stroustrup et d'autres qui n'ont pas été retenues pour le C++17—j'avais donné le lien dans les commentaires d'une précédente dépêche vendredi.
[^] # Re: Nouveau langage
Posté par Meku (site web personnel) . Évalué à 2.
Quel est le problème avec les fonctions membres, ou plutôt, pourquoi les fonctions libres seraient-elles mieux ?
[^] # Re: Nouveau langage
Posté par Oliver (site web personnel) . Évalué à 6.
Par exemple, la fonction suivante ne fonctionne que pour les structures (classes) fournissant des fonctions membres
recupere_x()
etrecupere_y()
.Supposons que nous devions utiliser deux bibliothèques développées par deux entités différentes :
recupere_x()
etrecupere_y()
;calcule
.On n'a pas la possibilité de modifier aucune des deux bibliothèques.
Comment faire pour passer la structure (classe) à la fonction
calcule
?Voyons maintenant, une implémentation de la fonction
calcule
utilisant cette fois-ci les fonctions libres :Et c'est beaucoup plus facile de passer la structure (classe) à la fonction
calcule()
. Deux possibilités :recupere_x()
etrecupere_y()
sont déjà disponibles dans une bibliothèque ;C'est dans ce second paradigme que sont conçus beaucoup de langages récents comme Rust et Go.
Cela permet naturellement de respecter le principe ouvert/fermé.
Prenons un exemple dans un vieux langage… allez prenons Python qui doit avoir une trentaine d'années, et étudions sa fonction libre
len()
:Certains objets implémentent la fonction membre
__len__()
mais la convention est de passer par la fonction librelen()
.Commentaire sous licence Creative Commons Zero CC0 1.0 Universal (Public Domain Dedication)
[^] # Re: Nouveau langage
Posté par djano . Évalué à 2.
Tu as oublié une autre solution: tu crée un adaptateur, ce qui grosso modo revient à implémenter des fonctions non-libres
recupere_x()
etrecupere_y()
(c'est pas bien plus compliqué qu'implémenter des fonctions libres).C'est la création de la classe adaptateur qui vous gêne?
[^] # Re: Nouveau langage
Posté par Oliver (site web personnel) . Évalué à 1.
Oui, tu as raison, une bonne façon de faire est de créer un Adaptateur. Mais le sujet de mon commentaire était de surligner l'intérêt des fonctions libres qui permettent d'étendre un objet de l'extérieur. Donc, j'avais volontairement omis les autres possibilités qui nécessitent plus de code, plus de relecture, plus de test, plus de maintenance… ;-) (bon oui, je l'accorde pas tellement plus)
Commentaire sous licence Creative Commons Zero CC0 1.0 Universal (Public Domain Dedication)
[^] # Re: Nouveau langage
Posté par djano . Évalué à 1.
Je commence à détecter un certain trait chez les développeurs C++: l'optimisite proactive aiguë!
[^] # Re: Nouveau langage
Posté par arnaudus . Évalué à 4.
Bah, je n'ai rien personnellement contre la programmation générique. C'est juste que le C++ OO et le C++ générique ressemblent de plus en plus à deux dialectes distincts, au moins autant que le C et le C++98. Et s'il est techniquement possible de mélanger les deux (le compilateur le comprend), c'est de plus en plus compliqué de les faire cohabiter dans le même projet. Mon impression est que de toutes manières les programmeurs ne vont plus pouvoir s'en sortir avec les deux paradigmes à la fois; d'un côté on aura le monde des design patterns et du typage dynamique, et de l'autre côté on aura les templates de templates et le typage statique.
Par contre, du coup, appeler tout ça "C++" et continuer à prétendre que c'est le même langage, ça n'est pas très sain. Pour recruter quelqu'un dans une boîte ou dans un projet, il va falloir préciser quels aspects du C++ on souhaite privilégier. De même, il pourrait être sympa de commencer à définir des sous-ensembles plus ou moins officiels qu'on pourrait passer aux compilateurs, pour vérifier qu'on respecte bien le cadre imposé. J'ai appris il y a peu de temps que pour émuler ce comportement, certains n'acceptaient que d'anciennes versions des compilateurs, ce qui me semble profondément stupide (on peut ne pas vouloir autre chose que du C++98 tout en voulant profiter des corrections de bugs et des optimisations des compilos récents).
Je ne pense pas que ça soit les templates qui fassent peur, c'est l'ensemble pas très intuitif des syntaxes associées.
[^] # Re: Nouveau langage
Posté par lmg HS (site web personnel) . Évalué à 6.
Ces paradigmes ne doivent pas être opposés. Ils offrent des choses complémentaires. Si je dois gérer mes observateurs à la main, je vais utiliser les classes génériques standards. Ne pas le faire serait totalement idiot de ma part.
Pareil, pour gérer la mémoire, par défaut je vais utiliser des
unique_ptr<>
qui sont génériques. Et je les mettrai dans des objets.Je comprends que devoir écrire ce genre de classe from scratch fasse peur à quelqu'un qui n'est pas habitué à la lourdeur de la syntaxe et à qui l'école n'a appris qu'un bout de l'OO (pour factoriser des données de bases de données et non pas pour factoriser des comportements) et du procédural. Mais pour la majorité d'entre nous, on n'a rien de tel à écrire. Juste à utiliser.
Reste que ce ne sont pas des paradigmes opposés.
Je dirai aussi, que le mélange est tout sauf récent. Cf la Thèse de Jim O Coplien qu'il a ultérieurement édité en livre: Multiparadigm Design in C++—cf la FAQ de dvpz pour les liens. Un des aspects les plus intéressants, c'est toute la partie sur la dualité commonalities et variability points. C'est le B à ba. On a des zones de code communes, et dedans, il y a des points où des détails vont varier. Et ça on sait le faire depuis longtemps: socket win32 ou socket POSIX ? Tableau d'entiers ou tableau de doubles ? Affichage de carrés, cercles, polygones ou autre figure géométrique ?
Toute la question est la dynamicité derrière les points de variations—et leur potentielle capacité à évoluer sans requérir de modification. Est-ce quelque chose que l'on sait déterminer dans le code source ? En fonction de la plateforme de build ? Est-ce lié à des plugins (choix du .so à charger)? Est-ce totalement dynamique ? Et bien en fonction de ça, ou va jouer avec des
#if
, on va compiler un .c ou un autre, on va avoir des instances d'un type ou d'un autre, ou on va choisir le paramètre template d'un type générique.Bref. C'est juste un autre levier qui offre plus de finesse. Et dans un même projet, il peut être intéressant de disposer de plusieurs façons pour procéder.
[^] # Re: Nouveau langage
Posté par arnaudus . Évalué à 10.
Et du coup, il faut combien de décennies d'apprentissage avant de savoir choisir le bon paradigme?
Je pense que personne ne considère qu'utiliser les conteneurs de la STL revient à faire de la programmation générique.
Je n'aime pas le fenouil braisé. Est-ce que ça veut dire que j'ai peur du fenouil braisé? Est-ce légitime de m'expliquer que la seule raison pour laquelle je n'aime pas le fenouil braisé est que je n'y suis pas habitué? Au bout d'un moment, c'est agaçant.
Si, parce qu'ils sont incompatibles, et qu'ils répondent tous les deux au même besoin de base (utiliser le même code pour appliquer les mêmes opérations à des objets différents qui partagent un certain nombre de propriétés). Si on va au-delà des simples conteneurs style STL, on se retrouve avec des possibilités d'architectures parallèles (d'un côté,
Truc<A>
etTruc<B>
, d'un autre côté TrucA et TrucB qui dérivent de Truc), avec chacun leurs paradigmes, leur syntaxe, leurs contraintes et leurs avantages. Mélanger les deux dans un projet un peu complexe me semble assez incongru, au moins autant que de mélanger des paradigmes C et C++, par exemple.[^] # Re: Nouveau langage
Posté par xcomcmdr . Évalué à 2.
C'est pas bien de ramener les gens à la réalité. :-p
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: Nouveau langage
Posté par lmg HS (site web personnel) . Évalué à 6. Dernière modification le 06 décembre 2016 à 11:51.
Combien de décennies faut-il pour savoir correctement concevoir? Je ne parle même pas de programmer, mais d'assimiler l'OO avec ses bonnes pratiques, le génie logiciel, la gestion des ressources, etc. Tout demande un investissement dans nos métiers—je sais que ce n'est pas ce que nos employeurs voudraient entendre.
Et pour savoir quoi choisir, la question, mes collègues savent toujours y répondre: est-ce un choix qui se fait à la compilation ? A l'exécution ? Au lancement ?
Après, j’admets volontiers que les choses deviennent compliquées quand on veut le beurre et l'argent du beurre. Exemple typique : un calcul sera appliqué sur des pixels d'images du spatial (en 10000x10000), mais la nature du calcul on ne la connait pas avant que l'utilisateur ne lance l'application. Là on veut un point de variation dynamique, et éviter de payer pour ce choix à l'exécution.
En termes de paradigmes, certains distinguent la programmation générique où l'on va utiliser, voire écrire des types génériques (comme on faisait en Ada sans que cela ne choque personne), et la métaprogrammation template où l'on va commencer à adapter automatiquement l'algorithme générique choisi en fonction des types que l'on manipule (p.ex. un tri sur une collection qui offre un accès direct et celui sur une collection qui n'offre qu'un accès séquentiel ne sera pas le même ;
std::copy
sur des POD pourra utilisermemcpy
, etc).Les trucs les plus avancés que j'ai fait dans du code métier, c'est définir des listes de types décrivant des informations pouvant être extraites d'une trame binaire (ordre, nb bits dans la trame, type C++ associé après décodage). J'ai fait ça par métaprog. D'autres décrivent les trames en XML et font des parseurs compliqués, ou des générateurs de code. Dans tous les cas, un investissement est requis pour la technique employée.
Pour le fenouil braisé, on a des mécanismes similaires : l'envie de creuser, le temps, l’honnêteté d'admettre que c'est adapté (ou non!!) à une situation. Il y a beaucoup de critères. L'essentiel de ces critères est humains. Je renvoie à la première partie de la dernière présentation de Dan Saks au CppCon2016. Çà fait bien 20ans (plus?) qu'il essaie de vendre le typage supérieur à 0 surcoût du C++ avec template à la communauté C embarqué. Dans la première partie de la vidéo, il revient sur ce qui s'est passé et les raisons (humaines) de son échec.
Si ceux qui connaissent le C++ sont convaincus que la généricité peut s'importer facilement, voire plus facilement qu'un conception OO de qualité (combien ont compris SOLID et en particulier le LSP, et ce qu'est véritablement l'encapsulation? Trop peu.), pourtant ça bloque.
Tu me dis que ce n'est pas parce que ça (te) fait peur. Pourquoi alors ?
PS:
Truc<T>
peut tout à fait hériter deITruc
ou deTrucImpl
. C'est même assez classique quand on veut combiner une variabilité dynamique avec une statique.[^] # Re: Nouveau langage
Posté par arnaudus . Évalué à 3. Dernière modification le 07 décembre 2016 à 14:45.
C'est super bancal comme solution, parce que ça demande une surcouche, et que l'interface n'est pas templatée. Prenins un exemple trivial : je veux faire un vecteur de vecteurs de différents types. On peut bien créer quelque chose comme
vector<MyVec*>
avec desMyvecT<T>
qui dérivent d'une classeMyVec
, mais à ma connaissance on ne peut pas avoir une méthodeMyVec::at(size_t i) const
qui retourne le bon type (*).Si la programmation générique était fongible avec la POO, alors le langage devrait assimiler un template à une interface, et autoriser des choses comme
vector * v;
qui se comporteraient comme des pointeurs vers des classes virtuelles pures. Je ne sais pas si c'est pour des raisons techniques ou philosophiques que le C++ a choisi des syntaxes incompatibles, mais je ne vois pas comment on peut l'interpréter autrement que par la volonté de définir deux dialectes qui ne sont pas destinés à cohabiter dans le même code.(
*
) Enfin si, je crois qu'on peut si la méthode retourne unvoid*
qu'on peut caster avec un typename qu'on aurait défini dansMyvec<T>
. Je ne sais pas s'il existe une personne sur terre qui pourrait croire que c'est une bonne idée.[^] # Re: Nouveau langage
Posté par lmg HS (site web personnel) . Évalué à 3.
OK, je pense voir ce que tu veux dire.
Tu es sur l'interface d'utilisation. J'étais sur POO pour l'interface et templates (qui ne doivent pas fuir au niveau de l'interface) pour l'implémentation—ce qui n'a rien de bancal. Effectivement, le C++ n'offre pas un polymorphisme paramétrique dynamique. En C++, le duck typing c'est 100% à la compilation.
Il y a feintes pour essayer de combiner tout ce beau monde. Cf les articles qui parlent de type erasure en C++—pas sûr que le même sens soit donné dans d'autres communautés.
Bref, il y a des cas de combinaison possibles sur une même famille de types. Et ça marche très bien. Le truc, c'est que dans ce cas, je ne veux pas d'un
at()
qui renvoie un template—enfin je ne veux jamais deat()
étant peu réception à la programmation défensive, mais c'est une autre histoire, je sais ne pas pouvoir vouloir d'unT ITruc::operator[]()
non plus—oui, de connaitre la limitation, ça oriente fortement ce que je m'autorise à vouloir faire.NB: l'équivalent template de l'interface, c'est le concept.
Pour les raisons, je pense qu'il faille aller chercher dans le technique. En C++, les template s'appliquent sur des scalaires comme des objets, et c'est assez contraignant. Je ne sais pas comment font C# et D sur cet aspect.
[^] # Re: Nouveau langage
Posté par lmg HS (site web personnel) . Évalué à 1.
s/peu réception/peu réceptif—il y a en d'autres, mais là ça ne veut vraiment plus rien dire…
[^] # Re: Nouveau langage
Posté par arnaudus . Évalué à 3.
Oui, donc dans les faits si tu ne veux pas utiliser le polymorphisme, bah la programmation à base de templates ne te pose pas de problème :-) Encore une fois, mon point de vue n'est pas de dire que la programmation générique c'est pourri, c'est de dire que le C++ OO et le C++ générique (au sens de templates non triviaux sur des objets complexes) sont philosophiquement et techniquement incompatibles. On peut concevoir tout un projet en C++ OO ou en C++ générique, mais ça va fortement conditionner le sous-ensemble du C++ et les designs qu'on va utiliser.
Bien sûr, on peut écrire des trucs hybrides, ça va compiler, et ça va faire d'excellents exercices pour les gens qui aiment se prendre la tête. La question, c'est plutôt "est-ce que des projets réels vont utiliser ça"?
[^] # Re: Nouveau langage
Posté par whity . Évalué à 3.
Ce n’est pas une question de langage, c’est aussi une question que certaines choses ne sont pas une bonne idée. Un grand classique, c’est le coup de si B dérive de A, alors vector dérive de vector qui est en réalité une très mauvaise idée (violation flagrante du LSP).
Ça m’est arrivé. Personnellement, je ne vois pas ça comme des incompatibilités, mais des complémentarités. Après, quand tu commences à voir les bénéfices du polymorphisme statique, tu as tendance à ne vouloir utiliser plus que ça :).
Mes commentaires sont en wtfpl. Une licence sur les commentaires, sérieux ? o_0
[^] # Re: Nouveau langage
Posté par lmg HS (site web personnel) . Évalué à 2.
Les projets réels les utilisent tout le temps.
- Je veux un tableau dans une classe concrète?
std::vector<>
. C'est générique et je m'en sers.- Je veux un truc qui va collecter automatiquement la mémoire ou n'importe quoi d'autre ?
std::unique_ptr<>
.- Je veux trier un tableau ?
std::sort()
- Je veux des images avec des types de pixel générique ? Ca marche aussi.
On ne va pas faire 100% dans un style et 100% dans un autre. On va prendre le style qui va bien pour un besoin donné. De la même façon que l'on ne va pas dériver pour le plaisir. On compose bien souvent à la place car cela offre plus de souplesse en ouvrant la porte au pattern Stratégie.
PS: Dans le monde des typeurs de canards cela que l'on nomme juste "polymorphisme" désigne le "polymorphisme paramétrique" qui en C++ correspond aux templates, et qui est statique (en C++).
[^] # Re: Nouveau langage
Posté par arnaudus . Évalué à 3.
J'ai l'impression qu'on ne se comprend pas, et au bout d'un moment ça tourne en rond. Je pense que personne ici ne parle de ne pas utiliser les conteneurs de la STL ; utiliser la STL n'a pas grand chose à voir avec la programmation générique.
La question (telle que je la comprend), c'est de choisir entre
et
comme paradigme de base. Sans aller jusqu'à prétendre qu'il faut 100% de l'un ou de l'autre, mon argument c'est que la plupart des problèmes ont une solution avec l'un ou l'autre, et que comme les deux sont très difficilement fongibles, on va orienter l'ensemble de l'architecture du programme dans un sens.
Je pense que c'est un excellent exemple. C'est générique? OK. Mais l'ergonomie est dégueulasse, parce que tu as oublié que ça s'utilisait comme ça :
std::sort(v.begin(), v.end());
. Évidemment, à force de voir ça, on est habitué, mais tu ne trouves pas quev.sort()
serait bien plus élégant? Il permettrait aussi le polymorphisme si tous les containers dérivaient d'une interface STL_cont. Bref, la programmation générique pour la bibliothèque standard, c'est un choix technique, mais ça me semble assez excessif de prétendre que c'est pratique et ergonomique ; d'une manière générale, la STL est relativement imbittable, les syntaxes sont contre-intuitives, et le code est assez illisible.[^] # Re: Nouveau langage
Posté par lmg HS (site web personnel) . Évalué à 5.
Utiliser la SL a tout à voir avec la programmation générique. Avant de disposer d'un
std::vector<>
, il faut l'écrire, et après libre à l'utilisateur de s'en servir. Convergeons vers ton exemple (hors STL mais dans la SL) il y astd::basic_string<>
ou mêmestd::basic_ostream<>
. Très peu ont conscience que ces trucs existent et pourtant ils s'en servent au travers des typedefsstd::string
,std::ostream
, ou carrément via la variable globalestd::cout
.Ces types sont génériques. Si les chaines ne piochent dans le paradigme OO que l'abstraction et l'encapsulation, les flux sont quant à eux plein d'héritage, multiple de surcroit, de points de variations dynamiques (ou comment filtrer à la volée un flux ou l'altérer pour justifier un texte p.ex.), de design pattern Stratégie, et je peux en oublier. Et ? Ils sont totalement génériques sur le type de caractères, et sur les descriptifs des caractères.
Nous sommes du côté d'une bibliothèque et pas d'un code métier. Et c'est probablement ça qui fait toute la différence. Côté métier offrir de la généricité est moins souvent pertinent. De fait une classe
EtatCivil
n'a pas grand intérêt à être générique. Côté bibliothèque j'ai pu travailler avec ITK et OTB, là on a des types images dans une hiérarchie avec pourtant un paramètre template pour le type de pixel. On a aussi des hiérarchies encore plus touffues pour dire qu'un truc assimilable à une image peut être une image, un fichier ou une transformation qui va servir à calculer une nouvelle image. Pour le coup ITK utilise des hiérarchies là où la STL (+ std::string) est 100% orientée concepts.Concernant
sort
, là tu bloques sur l'écriture OO mainstream on dirait. Parenthèse OO: Personnellement, je constate ici l'échec de Java qui comme le C++ a des types primitifs, mais qui a introduit un Top Type (type dont tout objet dérive). Résultat le code de divers algorithmes commesort
est dupliqué entre les tableaux primitifs et les collections à accès direct. Python n'a pas ce problème. Il y a un top type chez lui, mais pas de type primitif.Côté écriture de
sort
, la STL v2 est en cours de préparation. Le C++ assume totalement que la généricité est plus adaptée que des hiérarchies compliquées pour des algorithmes. L'écriture qui est sympa c'estsort(v)
pourquoi est-ce que cela devrait êtrev.sort()
? Avec CLOS, la syntaxe d'appel est(func x y z)
. Ce qui rend la gestion du dispatch multiple tout ce qu'il y a de plus naturel. Une petite discussion à ce sujet dans un article que j'avais bien aimé (le lien pointe directement sur le paragraphe qui discute s'il faut écrire kick the dog ou dog the kick).Pour en revenir à la STL v2, en plus de l'écriture
action::unique(action::sort(vi));
, elle va supporter l'écriturevi |= action::sort | action::unique;
qui marcheront aussi sur des tableaux natifs ou sur n'importe quel conteneur à accès direct (seulement? je n'ai pas vérifié) qui exposebegin()
etend()
en libre ou en membre.Pour la complexité de la STL, je dirai que pour un bonne part c'est une question d'habitude. Pour avoir lu et écouté Stepanov, ce à quoi il a abouti est naturel. Comme en maths, il voit que chaque algo a des prérequis pour être appliqué, à partir de là, hormis les
template <typename NomdeConcept1, ...
en début de signature, le reste est franchement clair. Après pour le code des implémentations de la SL, il y a la quasi obligation de tout préfixer avec des tirets-bas et la volonté d'auto-adaptativité à la nature des choses manipulées histoire d'optimiser (nous sommes en C++ après tout), ce qui ne rend pas la lecture toujours triviale. Plus des hacks pour éviter de produire des messages d'erreurs trop inintelligibles, plus de la programmation par contrat. Mais est-ce que cela nous concerne vraiment ?Je rajouterai aussi pour avoir essayé de jouer à ça dans ma jeunesse que le paradigme OO (tel qu'implémenté en Pascal/Delphi, C++ et Java) est totalement incapable de modéliser correctement les notions de groupes, anneaux et cie quant on commence à vouloir introduire du dispatch multiple dans des fonctions.
[^] # Re: Nouveau langage
Posté par kantien . Évalué à 4.
J'ai tendance à penser que cette limitation n'est pas propre aux différentes implémentations de la POO que tu cites, mais est inhérente au paradigme lui-même : la POO, qui met en avant la notion d'abstraction, c'est de l'abstraction vue par un enfant de quinze ans et à un moment, ça coince.
Dans un de ses commentaire, Olivier H disait : « Le mot-clé
template
fait peur, démystifions-le ;-) » : je suis impatient de lire une de vos dépêches spécifique à la description, au fonctionnement et à l'usage des templates.Juste une question : j'ai lu que le langage des template était Turing-complet, pourquoi lui avoir conféré cette propriété ? N'est-ce pas plutôt un défaut ?
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Nouveau langage
Posté par pulkomandy (site web personnel, Mastodon) . Évalué à 5.
C'était surtout un accident, au début :) Quelqu'un s'est dit: "hé, mais on peut faire un langage Turing complet avec ça!". Et ensuite y'a eu des gens pour s'en servir…
[^] # Re: Nouveau langage
Posté par lmg HS (site web personnel) . Évalué à 3.
J'ai aussi tendance à avoir cet avis, mais dans le doute (car je suis loin de connaitre les langage OO qui flirtent de très près avec le monde fonctionnel) j'ai préféré spécifier un contexte.
[^] # Re: Nouveau langage
Posté par kantien . Évalué à 5.
Je suis loin, mais alors très loin d'être un fin connaisseurs des langages de programmations existants, alors je me place surtout au niveau de l'approche paradigmatique.
Par exemple, en OCaml, il y a bien des objets mais la documentation officielle précise explicitement :
et ils sont de fait utilisés en conjonction avec les modules et foncteurs (qui sont ce qui se rapprochent des
template
du C++ dans ce langage), comme l'illustre le chapitre 5 sur les exemples avancés avec les classes et les modules. Ce qui rejoint ce que tu disais sur la complémentarité de l'OO et des templates en C++.De même, en Haskell, les type classes sont plus à rapprocher des templates que des classes de la POO (voir Demystifying type classes).
Là où pêchent inéluctablement la POO, c'est dans l'accès à certains niveaux d'abstraction, comme dans l'exemple proposé par arnaudus. Comme tu lui as répondu, pour du code métier, pouvoir faire de l'abstraction sur les types n'est pas nécessairement pertinent, en revanche pour la conception de bibliothèques, cela est plus que de la coquetterie.
Enfin, quand je lis ceci dans un des tes commentaires :
je me dis que l'on se rapproche bien plus de ce qu'est un concept, qu'avec les exemples de la POO du genre : un chat est un animal, donc il faut implémenter le concept de chat via une classe qui hérite de la classe animal.
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Nouveau langage
Posté par djano . Évalué à 2.
Oui en gros, c'est la différence entre typage nominal et typage structurel. Chacun a ses avantages et inconvénients. Le typage nominal peut offrir un niveau de sûreté de type très élevé, mais ça se fait au prix de la flexibilité. Le typage structurel est quand a lui extrêmement flexible et il passe partout.
[^] # Re: Nouveau langage
Posté par arnaudus . Évalué à 2.
Bah non, ma compréhension du problème est que la généricité de la fonction sort() impose l'utilisation d'itérateurs uniquement parce que les containers de la STL n'héritent pas d'une interface commune.
L'intuition est peut-être la chose au monde la moins partagée, mais pour moi les signatures "intuitives" de ces deux fonctions devraient être
Je trouve très surprenant en général que y = f(x) puisse modifier x, et les compilos récents n'ont aucun mal à optimiser v = sort(v) correctement. Ceci dit, j'ai peut-être tendance à tenter de retrouver en C++ des concepts qui viennent des langages de plus haut niveau.
On peut voter quelque part pour le support du Brainfuck dans C++19?
[^] # Re: Nouveau langage
Posté par pulkomandy (site web personnel, Mastodon) . Évalué à 3.
Là il faudrait faire de la programmation fonctionnelle, effectivement C++ n'est pas le meilleur choix pour ça.
Je suppose qu'ils ont voulu faire un truc qui ressemble aux "pipes" en shell unix?
[^] # Re: Nouveau langage
Posté par lmg HS (site web personnel) . Évalué à 3. Dernière modification le 08 décembre 2016 à 15:35.
C'est Alexandrescu, je crois, qui avait pondu un Iterators must go. C'était un des premiers articles de qualité pour pousser vers les remplacement des paires d'itérateurs par des plages (ranges en VO). Entre temps, il est parti vers le D, et je me demande si justement il n'avait pas participé aux ranges en D.
Bref, la STL v2 est dans cette mouvance. Et sur ce point, nous sommes d'accord, les algos de la STL v1 ne sont pas des plus ergonomiques. Ils ont de la souplesse, mais ils l'exigent de nous également.
C++20 le prochain je pense sinon. Et effectivement, il semblerait plutôt que l'on lorgne du côté des pipe UNIX. Sauf que … au lieu de se contenter d'une monde purement fonctionnel (de variables non modifiables), on traine le boulet OO des états qui sont altérés. D'où le
|=
. Dans les autres contraintes, il y a les générateurs à la Python.range::ints()
etiota()
peuvent ainsi générer un nombre (pseudo) infini d'entiers qui seront générés à la volée.[^] # Re: Nouveau langage
Posté par djano . Évalué à 2.
Justement, la version 10 de Java pourrait introduire les value types et ainsi émuler les templates C++ avec diverses spécialisations de code générique (comme les templates C++)
Par exemple, on pourrait enfin écrire
ArrayList<int>
et il aurait un vrai tableau d'int
derrière ça. À comparer avecArrayList<Integer>
qui est un tableau d'objets avec tous plein d'indirections en mémoire.Bon il faudrait déjà que Java 9 finisse par sortir. :-|
[^] # Re: Nouveau langage
Posté par groumly . Évalué à 2.
C'est pas la définition d'un programmeur c++ ça?
Linuxfr, le portail francais du logiciel libre et du neo nazisme.
[^] # Re: Nouveau langage
Posté par xryl669 . Évalué à 1.
Je suis tout à fait d'accord. Concernant la POO, le standard C++17 n'apporte rien de transcendant. Franchement, avoir des fonctionnalités d'introspection en 2017, je ne pense pas que ce soit si superflu (à l'heure où quasiment toute donnée est transmise en JSON). Il n'y a pas une seule bibliothèque C++ aujourd'hui qui sache faire de la sérialisation sans avoir à déclarer chaque champs 2 fois (une fois pour la compilation "statique" et une fois pour le runtime). C'est assez pénible.
De même, avoir des objets dynamiques, sans se taper des tuple à rallonge qui sont vraiment mauvais niveau praticité et performance et maintenabilité, à part pour la performance, c'est franchement manquant. Alors qu'il suffirait d'ajouter un opérateur pour "membre non trouvé" à gérer au runtime, du genre
Lorsque le compilateur rencontrerait un membre non présent, il appellerait l'opérateur "." (qui peut static_asserter si le nom n'est pas acceptable, ou remplir les champs au runtime.
[^] # Re: Nouveau langage
Posté par whity . Évalué à 3.
Certes, mais en même temps, exposer dans ta sérialisation le nom du membre (côté programme) est vraisemblablement une mauvaise idée. Outre que suivant le type de sérialisation voulue, celui ci peut nécessiter une transformation (par exemple, pour sérialiser vers xml, on aura tendance à transformer les « _ » en « - » ). Donc devoir le définir deux fois mais pas à proprement parler un soucis, en tout cas pas majeur.
De plus, si les objets sont simplement des conteneurs sans intelligence (par exemple, des objets correspondant à des enregistrements dans une base SQL), le code est souvent généré automatiquement.
Ça c’est une très mauvaise idée. Si j’appelle un membre qui n’existe pas, je m’attends à une erreur de compilation, pas une erreur à l’exécution. Changer ça dans le contexte de C++, c’est, quelque part, casser le langage.
Mes commentaires sont en wtfpl. Une licence sur les commentaires, sérieux ? o_0
[^] # Re: Nouveau langage
Posté par doom_Oo7 . Évalué à 2.
C'est bien pour ça que ça devrait être quelque chose d'implémentable côté bibliothèque.
Je pense qu'un des avantages du C++ c'est que faire des choix dans son code, ce n'est pas "casser le langage". Le langage nous offre des briques, et on est libre de construire ce que l'on veut avec. Avoir plus de briques n'est jamais une mauvaise chose, on est toujours libre de les laisser dans le bac à legos… mais par contre on peut toujours sortir la brique le jour ou on en a besoin (et j'ai déjà eu besoin plus d'une fois explicitement de cette fonctionnalité… c'est toujours possible de le refaire à la main ou avec des templates variadiques si on est motivé, mais bon).
[^] # Re: Nouveau langage
Posté par xryl669 . Évalué à 1. Dernière modification le 06 décembre 2016 à 14:06.
Je comprends ta remarque, mais ce dont tu parles c'est d'avoir la possibilité de filtrer le "nom" des membres. L'un n'empêche pas l'autre. Dans 95% des cas, tu veux un 1:1 entre la sérialisation et ta classe, donc le code devrait pouvoir faire cela directement, et pour les 5% restant, tu peux intercepter et/ou filtrer. La proposition d'introspection (qui sera dans C++20 probablement) le permettra justement.
Justement, c'est tout l'intérêt du
constexpr
ici. Par défaut, un tel opérateur entraînerait une erreur "membre machin non trouvé" donc le comportement sera 100% identique à l'état actuel.Par contre, si l'opérateur est présent, alors soit il est
constexpr
et peut être vérifié à la compilation (donc un comportement entre le mode dynamique/runtime et le mode figé/statique).Ceci serait très utile justement pour éviter les "outils" de génération qui écrivent du code illisible (type mock ou autre gsoap).
Exemple d'application, les membres namespace:attribute du XML, l'opérateur pourrait vérifier que le nom du membre "inconnu" que l'on veut vérifier commence par le nom du namespace attendu, par exemple.
Ou que les membres ajoutés commencent par "signal_" ou "slot_", si tu vois ce que je veux dire.
Ensuite, si l'opérateur n'est pas constexpr, le compilateur pourrait te jeter pour chaque appel dont le nom du membre est fixe à la compilation (avec un warning du genre "Ce serait mieux si tu ajoutais un membre machin à ta classe").
Enfin, tu l'utilises comme une classe dynamique au runtime (donc tu ne connais pas le nom des membres à priori), et tu utilises l'introspection pour les retrouver. C'est faisable actuellement avec une table de hash, mais c'est pas natif, donc pas optimal.
En bref, tu as le choix, c'est justement ça pour moi l'intérêt principal du C++
[^] # Re: Nouveau langage
Posté par whity . Évalué à 2.
J’ai un peu de mal à te suivre.
Je vais essayer de reformuler ce que j’ai compris. Tu souhaites que :
Foo foo;
foo.baz = "toto";
rajoute statiquement un membre baz de type string dans l’instance foo, et uniquement celle-ci ?
Ça casse tout le modèle de compilation C++, et c’est contraire à tout ce à quoi je m’attends quand je lis du C++ (c’est pour ça que je parlais de « casser le langage »). En plus, tu peux très bien obtenir ce résultat en surchargeant l’opérateur [] :
foo["baz"] = "toto";
Ce qui certes fait 3 caractères de plus à taper, mais est aussi lisible et beaucoup plus « dans l’esprit » du langage. Quant à l’idée que ce ne serait pas optimal, dans tous les cas, c’est un lookup dans une table de hachage (ou un dictionnaire), je ne suis pas sûr que l’intégrer au compilateur gagnera grand chose.
Mes commentaires sont en wtfpl. Une licence sur les commentaires, sérieux ? o_0
[^] # Re: Nouveau langage
Posté par groumly . Évalué à 3.
Dans la majorité des cas, non, ca change pas grand chose. C'est pas la meilleure idée de la création, mais c'est pas une hérésie non plus.
Dans les cas qui restent, regarde ce que fait Jackson en Java, avec un système d'annotations qui permet de d'abstraire a 100% du nom des champs, et de leur type. C'est foutremenr efficace, et si j'avais un truc pareil en swift/objc, je virerais direct 10% de mon code.
Linuxfr, le portail francais du logiciel libre et du neo nazisme.
[^] # Re: Nouveau langage
Posté par jcelerier . Évalué à 1. Dernière modification le 06 décembre 2016 à 00:14.
En attendant, on peut tricher un peu en faisant ça :
Avec GCC à -O3,
my_function
se simplifie.my_function(js_object&):
mov DWORD PTR [rdi+4], 1111
mov eax, 1111
ret
[^] # Re: Nouveau langage
Posté par xryl669 . Évalué à 1.
Oui, mais c'est lourd à écrire, à lire et donc à maintenir. C'est ça le problème.
# Syntaxe ?
Posté par whity . Évalué à 3.
Merci pour cette dépêche. Je suis un peu surpris par la syntaxe choisie. Je me serais attendu à quelque chose comme
static_if<cond> {
un peu sur le modèle du
static_assert
.Quelqu’un sait ce qui a motivé le choix de cette syntaxe ?
Mes commentaires sont en wtfpl. Une licence sur les commentaires, sérieux ? o_0
[^] # Re: Syntaxe ?
Posté par lmg HS (site web personnel) . Évalué à 4.
Une question facile :)
En C++, quand il s'agit d'ajouter quelque chose, ils cherchent avant toute chose à n'ajouter aucun nouveau mot clé. L'objectif est de n'introduire aucune régression sur des vieux codes qui compilaient. Ce qui fait que les évolutions se font en priorité dans la bibliothèque standard, puis par réutilisation/dépréciation de mots clés (cf
auto
).Avec
static_if
, il suffit d'une bibliothèque tierce (et je crois bien qu'il en existe justement) qui définit quelque chose avec ce nom, et cela plante définitivement la bibliothèque et tous les codes qui s'en servent.[^] # Re: Syntaxe ?
Posté par Chuck #1 . Évalué à 1.
Normalement, chaque bibliothèque a son espace de nommage donc ça ne plante que si on utilise la bibliothèque comme un goret (cf. le std:: devant les fonctions de la bibliothèque standard).
Cette signature est publiée sous licence WTFPL
[^] # Re: Syntaxe ?
Posté par lmg HS (site web personnel) . Évalué à 1.
Sauf si le nouveau truc est un mot clé.
Imagine une bibliothèque pré C++11 avec un
my::constexpr
. En C++11, ça ne peut plus compiler.[^] # Re: Syntaxe ?
Posté par Oliver (site web personnel) . Évalué à 2. Dernière modification le 05 décembre 2016 à 15:59.
Petite précision : Si le
static_assert()
devait être introduit aujourd'hui dans le C++ il aurait été renommé enconstexpr_assert()
car en C++ on essaye de faire la distinction entre la (les) sémantique(s) portée(s) par le mot-cléstatic
et celle deconstexpr
.Commentaire sous licence Creative Commons Zero CC0 1.0 Universal (Public Domain Dedication)
# Retour arrière sur l'OCP
Posté par lmg HS (site web personnel) . Évalué à 3.
Si cette évolution va simplifier l'écriture de fonctions récursives telles que les templates variadiques comme montré en exemple dans la dépêche, je redoute pour ma part un tour arrière sur le principe ouvert (aux évolutions) fermé (aux modifications).
Souvenez-vous, c'est le principe qui dit que dans un monde OO, les
if
c'est mal, et que les fonctions virtuelles c'est mieux. L'idée est que quand nous identifions des points de variations, plutôt que de modifier le code pour ajouter des nouveaux cas à coups deif
ou deswitch
, à la place, on prévoit un point de variation ouvert qui pourra accepter de façon plug-and-play des nouveaux cas non encore identifiés/définis.Si l'OO nous offrait un OCP dynamique, jusqu'à présent on employait des traits ou le SFINAE (c'est pas vraiment des traits le SFINAE) en métaprogrammation template. Pour ceux qui connaissent le Prolog (voire XSLT), on retrouve quelques part le principe de résolution par unification.
C'est sûr qu'un
if
c'est plus simple et plus accessible. Mais c'est beaucoup moins évolutif.[^] # Re: Retour arrière sur l'OCP
Posté par lmg HS (site web personnel) . Évalué à 0.
s/tour/retour
[^] # Re: Retour arrière sur l'OCP
Posté par Oliver (site web personnel) . Évalué à 3. Dernière modification le 05 décembre 2016 à 15:00.
C'est le principe ouvert/fermé.
Connu en anglais sous le nom open/closed principle.
(dans notre cas du C++, je trouve plus explicite le commentaire de lmg HS que l'article Wikipédia)
Souvent, on préfère un code simple et fermé à à code complexe mais ouvert (évolutif).
L'idée est d'avoir un code simple, facile à comprendre, et le jour où on a vraiment besoin de le faire évoluer, et bien on le réécrit.
Le risque d'avoir un code complexe mais ouvert est de garder la complexité et de ne jamais profiter de son ouverture.
Je précise, je suis pour le principe ouvert/fermé. Je dis juste que des fois (voir souvent) ce n'est pas justifié.
Selon le contexte, on utilisera :
if constexpr
pour du code simple et fermé ;Commentaire sous licence Creative Commons Zero CC0 1.0 Universal (Public Domain Dedication)
[^] # Re: Retour arrière sur l'OCP
Posté par whity . Évalué à 1.
Je ne suis pas trop d’accord avec toi (du moins, avec ce que tu as écris). Tu donnes l’impression que ouvert et fermé s’opposent, alors que dans l’OCP, ils se complètent (n’agissent pas sur la même dimension). L’article wikipédia en français est assez clair là-dessus.
La complexité du code n’a pas nécessairement grand chose à voir là-dedans (au contraire, bien mis en œuvre, l’OCP a tendance à simplifier l’architecture globale car il réduit les effets de bord).
Mes commentaires sont en wtfpl. Une licence sur les commentaires, sérieux ? o_0
[^] # Re: Retour arrière sur l'OCP
Posté par Oliver (site web personnel) . Évalué à 3.
Oui, tu as raison whity, merci. Je corrige :-)
Je résume le commentaire de lmg HS qui en bref disait que nous avons le choix entre :
if constexpr
pour du code simple ;Voici mon commentaire corrigé
if constexpr
simplifie le code et tan pis pour le principe ouvert/fermé.Car souvent, on préfère un code simple plutôt qu'un code complexe mais ouvert/fermé (évolutif).
L'idée est d'avoir un code simple, facile à comprendre, et le jour où on a vraiment besoin de le faire évoluer, et bien on le réécrit.
Le risque d'avoir un code complexe mais ouvert/fermé est de garder la complexité et de ne jamais profiter de son principe ouvert/fermé.
Je précise, je suis pour le principe ouvert/fermé, et c'est mieux quand on peu allier simplicité à ouvert/fermé.
Je dis juste que des fois (voir souvent) complexifier n'est pas justifié, vaut mieux avoir simple et risquer tout casser.
Commentaire sous licence Creative Commons Zero CC0 1.0 Universal (Public Domain Dedication)
# Correction § "Remplacement du SFINAE"
Posté par Oliver (site web personnel) . Évalué à 3. Dernière modification le 05 décembre 2016 à 15:09.
Le code suivant est utilisé dans la dépêche, mais il est ambigu car on ne voit pas la différence au niveau de la déclaration des deux fonctions :
Merci à un modérateur de le remplacer par :
Commentaire sous licence Creative Commons Zero CC0 1.0 Universal (Public Domain Dedication)
[^] # Re: Correction § "Remplacement du SFINAE"
Posté par Benoît Sibaud (site web personnel) . Évalué à 2.
Corrigé, merci.
# Je m'y colle...
Posté par windu.2b . Évalué à 10.
Puisqu'il faut demander, je m'y colle : on pourra avoir une dépêche sur le SFINAE ? Parce que j'ai à peu près rien compris ! Comme ça, je n'aurai sans doute toujours rien compris, mais j'aurai plus à lire ! :-)
[^] # Re: Je m'y colle...
Posté par Oliver (site web personnel) . Évalué à 3. Dernière modification le 05 décembre 2016 à 15:45.
OK on rajoute ça dans le tuyau ;-)
On commencera par quelques petites dépêches sur la méta-programmation, puis on attaquera gentiment le SFINAE ^
Mais soit patient, ça risque d'être pour l'année prochaine !
Commentaire sous licence Creative Commons Zero CC0 1.0 Universal (Public Domain Dedication)
[^] # Re: Je m'y colle...
Posté par whity . Évalué à 3.
En attendant, il y a une explication relativement claire en français ici.
Mes commentaires sont en wtfpl. Une licence sur les commentaires, sérieux ? o_0
[^] # Re: Je m'y colle...
Posté par Morovaille . Évalué à 1.
Hum, en fait je crois que comme M. Jourdain qui faisait de la prose sans le savoir je faisais de la SFINAE. C'est une des bases de la métaprogrammation en fait, tout simplement. Si on en a fait un tout petit peu, on a forcément exploité cette technique.
Ce commentaire est libre de droit, vous pouvez le réutiliser comme bon vous semble.
[^] # Re: Je m'y colle...
Posté par barmic . Évalué à 3.
Oui c'est pour ça que je ne vois pas trop pourquoi en faire un article (avec 2 articles d'introduction en plus !).
Mais je rate probablement quelque chose…
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Je m'y colle...
Posté par Gabbro . Évalué à 4.
N'ayant pas compris un traitre mot du lien ci-dessus, je suis favorable à un article, ou un autre lien qui supposerait moins de connaissance de la part du lecteur.
Parce que j'ai pas mal entendu parlé de
template
et de métaprogrammation, mais je n'ai jamais compris ce que c'était (ni à quoi ça sert).[^] # Re: Je m'y colle...
Posté par Gof (site web personnel) . Évalué à 2.
Pas facile en effet de trouver de bonnes explication en français de SFINAE. Google me donne ceci: http://h-deb.clg.qc.ca/Sujets/Divers--cplusplus/SFINAE.html
Est-ce que ça aide ?
Le problème n'est peut être pas SFINAE, mais la métaprogrammation tout court.
Quelques liens:
http://loulou.developpez.com/tutoriels/cpp/metaprog/
http://h-deb.clg.qc.ca/Sujets/Divers--cplusplus/Metaprogrammation.html
[^] # Re: Je m'y colle...
Posté par Morovaille . Évalué à 6. Dernière modification le 06 décembre 2016 à 10:05.
C'est de la programmation fonctionnelle à la compilation. Un bon exemple est la fonction factorielle.
Tu définis une structure
factorial
qui dépend d'un paramètre template qui est un entier :À l'intérieur tu définis le cas général :
constexpr
veut dire que c'est calculé à la compilation. C'est faisable puisqu'on a toutes les infos à la compilation. Le code est simple,value
est égal au rang actuel multiplié par factorielle du rang moins un.Comme dans toute programmation récursive (la programmation fonctionnelle se fait en récursion), il faut une condition d'arrêt :
La valeur de factorielle de 0 est un. C'est ici que la récursion s'arrête.
Un programme complet pour montrer le code :
factorial<0>::value
etfactorial<4>::value
sont connus à la compilation, rien n'est calculé au runtime.Cet exemple là n'est pas très utile, mais il existe des cas où ces technique améliorent beaucoup la rapidité du code en précalculant des choses à la compilation. Glander sur http://stackoverflow.com/questions/tagged/metaprogramming%20c%2b%2b peut donner quelques exemples d'application.
Ce commentaire est libre de droit, vous pouvez le réutiliser comme bon vous semble.
[^] # Re: Je m'y colle...
Posté par Gabbro . Évalué à 1.
Merci à vous deux. Si j'ai bien compris, SFINAE, c'est simplement l'idée d'aller chercher la fonction la plus spécialisée ; ça me fait penser au
select type
du fortran 2003.Pour le
constexpr
, de ce que je lisais sur les sites donnés, il n'y a même pas besoin de template. C'est juste un moyen simple de pré-calculer des valeurs, tout en les calculant à l’exécution lorsque c'est impossible à la compilation.[^] # Re: Je m'y colle...
Posté par lmg HS (site web personnel) . Évalué à 5.
Le SFINAE est un outil qui sert à détecter des informations non triviales ou des possibilités par essai et erreur. Sauf que les erreurs sont ignorées et à la place on se débrouille pour récupérer un truc que l'on va assimiler à faux. Ce booléen on s'en sert ensuite ailleurs pour choisir quelle spécialisation nous intéresse.
Exemple à la C++98
Façon C++14 (voire 17), on a de nouveaux outils:
# SFINAE
Posté par OhMyGod . Évalué à 1.
Deux vidéos intéressantes sur la metaprogrammation et les SFINAE :
CppCon 2014: Walter E. Brown "Modern Template Metaprogramming: A Compendium (partie 1 et 2)
https://www.youtube.com/watch?v=Am2is2QCvxY
https://www.youtube.com/watch?v=a0FliKwcwXE
# dans l'exemple, is_function ne marche pas, il faut utiliser is_member_funciton_pointer
Posté par DerekSagan . Évalué à 1.
Dans l'exemple donné avec if_function, en fait ça ne marche pas avec gcc 7 ni le dernier clang, parce que T::f n'est pas une fonction statique.
Voir ici l'erreur de compilation:
https://godbolt.org/g/qIPNxg
En revanche avec is_member_function_pointer on y arrive:
https://godbolt.org/g/NNbYBw
Il y a peut-être d'autre façon de corriger, je ne suis pas un gourou méta-programmation.
L'exemple cité dans le corps de la dépêche ne compile que parce que le template n'est pas instancié mais seulement défini.
Voilà, vivement c++17, et merci pour la dépêche instructive.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.