IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

auto ou const auto pour les lambdas ?


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 492
    Billets dans le blog
    1
    Par défaut auto ou const auto pour les lambdas ?
    Bonjour

    Je suis de la team "const autant que possible". Donc, dès que je vois une déclaration de variable à laquelle je peux ajouter const, je le fais.

    Je fais une exception à cette règle : quand je stocke une lambda expression, je n'ajoute jamais const. Je fais auto foo = []() {}; et non const auto foo = []() {};.

    Pourtant, en suivant la logique "const autant que possible", je devrais aussi utiliser const dans cette situation.

    Comment faites-vous ? auto ou const auto pour les lambdas ? Pourquoi ?

    PS : pour celles et ceux qui ne savent pas, on ne peut changer la valeur de la variable :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main() {
        auto f = []() {};
        f = []() {};
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    <source>:3:7: error: no viable overloaded '='
        3 |     f = []() {};
          |     ~ ^ ~~~~~~~
    <source>:2:14: note: candidate function (the implicit copy assignment operator) not viable: no known conversion from '(lambda at <source>:3:9)' to 'const (lambda at <source>:2:14)' for 1st argument
        2 |     auto f = []() {};
          |              ^
    1 error generated.
    Compiler returned: 1
    EDIT : on peut produire un exemple où le typage correspond et où l'affectation est quand même rejetée (de toute façon, c'est pas un cas très utile) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main() {
        auto f = []() {};
        auto g = f;
        f = g;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    <source>:4:6: error: object of type '(lambda at <source>:2:14)' cannot be assigned because its copy assignment operator is implicitly deleted
        4 |         f = g;
          |           ^
    <source>:2:14: note: lambda expression begins here
        2 |     auto f = []() {};
          |              ^

  2. #2
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    A priori je suis d'accord qu'il faudrait un const.

    Cela dit, j'ai une réserve sur ton exemple.
    Chaque lambda est d'un type unique. Du coup, dans ton exemple, tu essaies d'affecter deux types non compatibles.

    Par contre, j'ai passé dix minutes à trouver un contre exemple, et j'arrive quand même à un refus.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <iostream>
    int main() {
        int state = 0;
        auto f = [state]() mutable { return ++state; };
        auto backup = f;
        auto g = f;
        for (int i = 0; i < 10; ++i) std::cout << f() << ' ';
        for (int i = 0; i < 10; ++i) std::cout << g() << ' ';
        f = backup;
        return 0;
    }
    Avec GCC, en C++17, ce code-ci échoue avec le message suivant, mais uniquement à la ligne f = backup;.
    error: use of deleted function ‘main()::<lambda()>& main()::<lambda()>::operator=(const main()::<lambda()>&)’

  3. #3
    Membre Expert Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 048
    Par défaut
    Hello,
    Cela fait longtemps que je ne suis pas venu ici !
    Ça n'a pas trop de sens d'avoir un lambda const car par defaut l'operator()est const.

    Une lambda ce n'est rien de plus que du sucre syntaxique d'un foncteur, donc si f est const il ne peux modifier son état dans l'operator(), donc ne peut modifier ces variables internes comme toutes méthodes const d'une classe, or l'operator() étant const par défaut, this est const par défaut dans l'operator().

    Cela n'apporte rien.

  4. #4
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 492
    Billets dans le blog
    1
    Par défaut
    Mon seul bon argument pour ne pas ajouter const est effectivement que ça ne sert à rien, la variable étant en quelque sorte "implicitement const". L'autre argument que je peux avoir c'est "ça met plus en évidence la lambda", mais il me semble un peu léger. J'ai l'impression que personne n'a de bons arguments pour ne pas mettre const

    Les raisons techniques du langage derrière ne sont pas vraiment intéressantes dans un document de "code style", et ce n'est d'ailleurs pas le sujet ici

  5. #5
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Citation Envoyé par Bktero Voir le message
    J'ai l'impression que personne n'a de bons arguments pour ne pas mettre const
    Ce qui est en soit une bonne raison pour le mettre.

    Je préfère être explicite, et je cite les C++ Core Guidelines:
    I.1: Make interfaces explicit
    ES.25: Declare an object const or constexpr unless you want to modify its value later on

  6. #6
    Membre Expert Avatar de gabriel21
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2007
    Messages : 548
    Par défaut
    Pourquoi alourdir le code si de toutes les façons nous ne pouvons pas modifier un lambda ?

    Est-il utile d'expliciter un état qui ne peut être intrinsèquement autre ?
    La règle du const tient parce qu'une variable peut être modifiée ou pas. Cela permet d'expliciter la volonté du programmeur voir du modeleur dans les cas où plusieurs options sont possible. J'ai tendance à mettre le const dans les modèle UML.

  7. #7
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 635
    Par défaut
    Salut,
    Citation Envoyé par ternel Voir le message
    Ce qui est en soit une bonne raison pour le mettre.

    Je préfère être explicite, et je cite les C++ Core Guidelines:
    I.1: Make interfaces explicit
    ES.25: Declare an object const or constexpr unless you want to modify its value later on
    Et tu as tout à fait raison avec ce point. Il faut juste se mettre d'accord sur les termes que l'on utilise...

    Car la ligne directrice ES25 parle d'objets, et non d'expressions. C'est donc qu'il est utile de faire la distinction entre les expressions qui représentent effectivement objets -- comme les données et les constantes -- et les expressions qui ne représentent pas des objets, comme les fonctions.

    Or, les expressions lambda sont plus proche des fonctions que des objets, ce qui fait qu'il n'y a finalement que peut de raison de les déclarer constantes.

    Tu pourras, bien sur, me dire que les fonction peuvent renvoyer une valeur constante, et que l'on peut même trouver facilement une situation dans laquelle c'est effectivement la fonction qui est déclarée constante (lorsque l'on a affaire à une fonction membre).

    Dans le premier cas, cela ne change rien, vu que toutes les fonctions ne renvoient pas forcément une donnée, et que la constance de la donnée renvoyée n'a -- en définitive -- absolument rien à voir avec le comportement de la fonction en elle-même.

    Dans le deuxième cas (les fonctions membres constantes), la constance n'a pour but que d'indiquer le fait que la donnée à partir de laquel la fonction sera appelée ne sera pas modifiée. Ce qui nous place bel et bien sur une constance d'objet...

    Lorsque tu assignes une expression lambda à f (ou à g, ou à tout ce que tu peux vouloir) sous la forme de f =[](){}, tu crées d'avantage un alias sur une expression (f étant au final une expression) qu'un objet (une donnée dont le type serait l'expression elle-même), le mot clé auto étant là pour représenter le retour de l'expression dans le cas où l'expression serait destinée à renvoyer une valeur.

    Au final, nous pourrions dire que "oui, il faut rendre tous les objets que l'on peut constants, à moins d'avoir de bonnes raisons de croire qu'ils devront être modifiés", dans le respect de la ES25; cependant, il faut se rendre compte que seules les données sont susceptibles d'être considérées comme des objets
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. Réponses: 10
    Dernier message: 07/11/2010, 23h53
  2. Auto completion pour les facelets xhtml
    Par BugFactory dans le forum Eclipse Java
    Réponses: 1
    Dernier message: 17/09/2009, 10h24
  3. Réponses: 1
    Dernier message: 24/06/2009, 10h37
  4. Auto-complétion pour les mots clés Begin/End
    Par Alex Laforest dans le forum EDI
    Réponses: 2
    Dernier message: 21/09/2005, 21h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo