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

Langage C++ Discussion :

constexpr et std::min


Sujet :

Langage C++

  1. #1
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut constexpr et std::min
    Bonjour à tous,

    Le code suivant ne compile pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    struct A
    {
        static constexpr int a = 42;
    };
     
    int main()
    {
        return std::min(A::a, 12);
    }
    Avec l’erreur suivante :
    undefined reference to `A::a'
    Bon, de ce que je comprends, c’est lié au passage par référence constante.

    Toutefois, je ne comprends pas (note : ce n’est pas lié au constexpr, ça fait pareil avec un const simple). Je pensais qu’il était parfaitement valide d’initialiser les variables statiques de type int dans la classe. Or, je constate que oui, c’est valide, mais que la variable est déclarée, a une valeur, mais pas d’adresse .

    Le comportement est le même avec gcc et clang, ce qui incite à penser que c’est normal. Pourtant, je ne peux pas m’empêcher de trouver ça particulièrement tordu.

    D’autres avis / explications ?

  2. #2
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Par défaut
    http://cpp.developpez.com/faq/cpp/?p...SS_init_static

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #include <iostream>
    using namespace std;
     
     
    struct A
    {
        static constexpr int a = 42;
    };
     
    constexpr int A::a;
     
    int main()
    {
        std::cout<<std::min(A::a, 12)<<std::endl;
        std::cout<<std::min(A::a, 666)<<std::endl;
        return 0;
    }
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  3. #3
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    La FAQ dit bien :

    il existe un raccourci pour les variables statiques entières constantes, voir Que signifie la déclaration suivante : 'static const int MAX = 10' ?
    Et c’est bien ce qui m’ennuie ici.

    Le « raccourci » n’est pas équivalent, en fait.

  4. #4
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Bon, je me réponds à moi-même, je suis allé regarder la norme :

    § 9.4.2
    If a static data member is of const literal type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression.
    A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. — end note ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.
    La dernière phrase est celle qui est importante ici, même si je ne comprends pas tout ce qu’elle veut dire…

  5. #5
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Par défaut
    constexpr implique const, mais pas trop quand même.
    Preuve :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    #include <iostrema>
    using namespace std;
     
    struct A
    {
        static constexpr const int a = 42;
    };
     
     
    int main()
    {
        std::cout<<std::min(A::a, 12)<<std::endl;
        std::cout<<std::min(A::a, 666)<<std::endl;
        return 0;
    }
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  6. #6
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Tu compiles avec quel compilateur ? Visual ?

    Chez moi, j’ai bien l’erreur de lien avec gcc (4.7.2 ou 4.8.1) et clang (3.0 et 3.2)

  7. #7
    Membre très actif

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Par défaut
    Ce qui m'étonne plus personnellement c'est que tu puisse initialiser a comme tu essaies de le faire. Je sais que le C++11 le permet dorénavant, mais je ne savais pas qu'il le permettait pour une déclaration d'une variable statique qui n'est pas encore définie (d'où le fait qu'elle n'ai pas d'adresse).


    L'équivalent de ce que tu cherches à faire serait peut-être ceci (code pas testé):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    struct A
    {
        static constexpr int a;
    };
     
    constexpr int A::a = 42;
     
    int main()
    {
        return std::min(A::a, 12);
    }
    Sinon, par rapport à la définition que tu as trouvé dans la norme, je crois que cela veut dire que tu peux faire exactement ce que tu as écris, mis à part qu'il faille toujours définir ta variable ailleurs comme n'importe quelle variable statique. J'avoue que le coup de pouvoir initialiser une variable statique alors qu'elle n'est pas définie est assez étonnant de prime abord, maintenant ce n'est qu'une écriture syntaxique, je me demande ce qui se passe réellement dessous..


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    struct A
    {
        static constexpr int a = 42 ;
    };
     
    constexpr int A::a;
     
    int main()
    {
        return std::min(A::a, 12); //devrait fonctionner d'après la norme
    }

  8. #8
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Citation Envoyé par Kaamui Voir le message
    Ce qui m'étonne plus personnellement c'est que tu puisse initialiser a comme tu essaies de le faire. Je sais que le C++11 le permet dorénavant, mais je ne savais pas qu'il le permettait pour une déclaration d'une variable statique qui n'est pas encore définie (d'où le fait qu'elle n'ai pas d'adresse).
    C’est autorisé pour les int (et uniquement les int) depuis au moins 2003, peut-être bien depuis 98. C++11 l’a étendu aux types avec initializer list si je ne me trompe pas.

    Je le fais depuis longtemps, et je suis seulement aujourd’hui tombé sur le problème avec std::min (en fait, avec n’importe quelle fonction prenant un const int &, ce qui n’est forcément pas légion).

    Et effectivement, la solution que toi et david proposez (définir la variable dans le .cpp, comme pour une autre variable statique) fonctionne bien. Mais je m’interroge sur la nécessité de le faire. Ça ressemble à un fail, quelque part.

  9. #9
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Tu compiles avec quel compilateur ? Visual ?

    Chez moi, j’ai bien l’erreur de lien avec gcc (4.7.2 ou 4.8.1) et clang (3.0 et 3.2)
    J'ai pas de compilo sous la main alors je teste avec http://ideone.com/.
    avec le choix de C++11 comme valeur de langage.

    Je pense qu'il utilise g++ et/ou clang sous le capot.

    Edit
    Et effectivement, la solution que toi et david proposez (définir la variable dans le .cpp, comme pour une autre variable statique) fonctionne bien. Mais je m’interroge sur la nécessité de le faire. Ça ressemble à un fail, quelque part.
    Soit c'est

    • static + constexpr + const et la pas besoin de définition dans le cpp
    • static + constexpr et la faut une définition dans le cpp
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  10. #10
    Membre très actif

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    C’est autorisé pour les int (et uniquement les int) depuis au moins 2003, peut-être bien depuis 98. C++11 l’a étendu aux types avec initializer list si je ne me trompe pas.
    Ah Ok. Je ne savais pas que c'était déjà autorisé pour le type int.

    Citation Envoyé par white_tentacle Voir le message
    Et effectivement, la solution que toi et david proposez (définir la variable dans le .cpp, comme pour une autre variable statique) fonctionne bien. Mais je m’interroge sur la nécessité de le faire. Ça ressemble à un fail, quelque part.
    Personnellement ça me parait assez logique et nécessaire vue la nature des variables statiques. Pour moi c'est plus l'initialisation qui créé la fausse impression de la définition de la variable. Comme ce n'est pas une donnée membre, mais bien un attribut statique de la classe, c'est normal que sa définition ne soit pas dépendante d'une instanciation particulière de cette même classe. Du coup je soupçonne fortement que le coup de l'initialisation à la déclaration dans la classe ne soit qu'un sucre syntaxique, pour un attribut statique.

  11. #11
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Citation Envoyé par Kaamui Voir le message
    Du coup je soupçonne fortement que le coup de l'initialisation à la déclaration dans la classe ne soit qu'un sucre syntaxique, pour un attribut statique.
    Oui. Mais j’ai toujours pensé que c’était équivalent (et d’ailleurs, la FAQ ici parle bien d’un « raccourci »). Or, ce n’est pas tout à fait le cas…

    static + constexpr + const et la pas besoin de définition dans le cpp
    Chez moi, même ça ne passe pas avec gcc 4.8.1 / c++11…

  12. #12
    Membre chevronné
    Inscrit en
    Juillet 2012
    Messages
    231
    Détails du profil
    Informations forums :
    Inscription : Juillet 2012
    Messages : 231
    Par défaut
    À priori, Ideone utilise gcc 4.8.1 aussi.
    Cela dit, je ne sais pas avec quelles options ils compilent mais dès que l’on passe en O1 ça compile sans souci (grâce aux optimisations bien sûr, les appels doivent sauter et du coup pas de problème).
    Par contre, compilation sans optimisations on retombe sur ton message d’erreur.
    Ça pourrait expliquer pourquoi ça passe chez eux et pas chez toi alors que même vous utilisez le même compilo’ et la même version, mais ça n’est qu’une supposition.

  13. #13
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Citation Envoyé par grim7reaper Voir le message
    À priori, Ideone utilise gcc 4.8.1 aussi.
    Cela dit, je ne sais pas avec quelles options ils compilent mais dès que l’on passe en O1 ça compile sans souci (grâce aux optimisations bien sûr, les appels doivent sauter et du coup pas de problème).
    Par contre, compilation sans optimisations on retombe sur ton message d’erreur.
    Ça pourrait expliquer pourquoi ça passe chez eux et pas chez toi alors que même vous utilisez le même compilo’ et la même version, mais ça n’est qu’une supposition.
    Effectivement, avec les optims, ça passe avec gcc (mais toujours pas avec clang). Je vois bien pourquoi, mais l’effet de bord est amusant.

  14. #14
    Membre chevronné
    Inscrit en
    Juillet 2012
    Messages
    231
    Détails du profil
    Informations forums :
    Inscription : Juillet 2012
    Messages : 231
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Je vois bien pourquoi, mais l’effet de bord est amusant.
    Tu peux expliquer alors ?
    Parce moi je ne vois pas pourquoi ça ne passe pas avec clang (ou je ne vois pas pourquoi ça passe avec gcc, au choix ^^).
    En général, quand des compilo’ réagissent différemment c’est parce qu’il y a un undefined behavior (ou assimilé).
    C’est le cas ici ?

  15. #15
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    C’est une erreur de link : Symbole non trouvé à l’édition de lien. Les optimisations de gcc dégagent complètement le symbole (le std::min est en fait résolu à la compilation, mais ça marche aussi si on met une variable pour forcer l’appel, on retrouve la constante 42*dans l’assembleur et pas une référence), alors que probablement celles de clang ne le font pas.

    Ça donne comme effet de bord un code qui ne compile pas sans les optimisations, mais compile par effet de bord avec les optimisations. Amusant

  16. #16
    Membre chevronné
    Inscrit en
    Juillet 2012
    Messages
    231
    Détails du profil
    Informations forums :
    Inscription : Juillet 2012
    Messages : 231
    Par défaut
    Ha, c’était une erreur de link, pas de compilation. Ok, je vois.

  17. #17
    Membre Expert

    Avatar de germinolegrand
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Octobre 2010
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Octobre 2010
    Messages : 738
    Par défaut
    Préparez-vous à mettre des const devant vos constexpr, à partir de C++14 constexpr n'implique plus const

  18. #18
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Citation Envoyé par germinolegrand Voir le message
    Préparez-vous à mettre des const devant vos constexpr, à partir de C++14 constexpr n'implique plus const
    Je suppose qu’il y a une bonne raison à ça, mais là je ne vois pas laquelle. Une constante de compilation variable au runtime ?

  19. #19
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  20. #20
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    D’accord, je comprends mieux. Merci pour le lien

Discussions similaires

  1. Hebergement jsp servlets(gratuit pour un espace min)
    Par Gandalf_new dans le forum Servlets/JSP
    Réponses: 6
    Dernier message: 09/01/2010, 05h04
  2. Équivalent de std::min et std::max en C?
    Par vdumont dans le forum C
    Réponses: 2
    Dernier message: 08/10/2006, 18h15
  3. [Algo] Convertir un entier en HH:min:ss
    Par Thomas Lebrun dans le forum Algorithmes et structures de données
    Réponses: 6
    Dernier message: 26/02/2004, 23h57
  4. std MFC
    Par philippe V dans le forum MFC
    Réponses: 7
    Dernier message: 17/01/2004, 00h54
  5. STL : std::set problème avec insert ...
    Par Big K. dans le forum MFC
    Réponses: 13
    Dernier message: 08/11/2003, 01h02

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