36 votes

Modifier une variable globale dans une fonction constexpr en C++17

En C++17, peut-on modifier les variables globales dans un fichier constexpr fonction ?

#include <iostream>

int global = 0;

constexpr int Foo(bool arg) {
    if (arg) {
        return 1;
    }
    return global++;
}

int main() {
    std::cout << global;
    Foo(true);
    std::cout << global;
    Foo(false);
    std::cout << global;
}

Je ne m'attendais pas à ce que vous puissiez le faire, mais Clang 6 le permet : https://godbolt.org/g/UB8iK2

Le CCG, quant à lui, ne le fait pas : https://godbolt.org/g/ykAJMA

Quel est le bon compilateur ?

1 votes

@AnT - J'ai besoin d'une feuille de contrôle pour garder les contraintes C++11, C++14 et C++17 en ordre.

0 votes

Aucune ne fonctionne si vous forcez l'évaluation au moment de la compilation. constexpr int a = Foo(false) mais je ne sais pas si l'un ou l'autre est incorrect.

2 votes

Il me semble qu'il s'agit d'un bogue de base dans gcc.

21voto

codekaizer Points 4295

Quel est le bon compilateur ?

Clang a raison.

La définition d'un constexpr conformément à l'article dcl.constexpr/3

La définition d'un constexpr doit satisfaire aux conditions suivantes suivantes :

(3.1) son type de retour doit être un type littéral ;
(3.2) chacun de ses types de paramètres est un type littéral ;
(3.3) son organe fonctionnel est le suivant = delete , = default , qui fait pas contenir :

(3.3.1) une définition asm,
(3.3.2) une instruction goto,
(3.3.3) une étiquette d'identification,
(3.3.4) un bloc d'essai, ou
(3.3.5) a définition d'une variable de type non littéral ou de statique ou la durée de stockage du fil ou pour laquelle aucune initialisation n'est effectuée.

Également selon dcl.constexpr/5 :

Pour un constexpr ou un constructeur constexpr qui n'est ni par défaut ni un modèle, si aucune valeur d'argument n'existe s l'invocation de la fonction ou du constructeur pourrait être a d'une expression constante de base,

Foo(true) pourrait être évaluée à un expression de la constante de base (c'est-à-dire 1 ).

En outre, Foo(false) pourrait être mais il n'est pas nécessaire qu'elle soit évaluée en permanence.

CONCLUSION

Ainsi, un insecte dans le CCG.


Merci à @Barry, @aschepler et @BenVoigt pour m'avoir aidé à répondre à cette question.

1 votes

C'est nettement plus clair. Je crois qu'il est en fait impossible pour le compilateur de raisonner sur la valeur de global même s'il inline Foo(false) en principal, car global a un lien externe. (Il n'est pas nécessaire que le résultat soit 0\n0\n1 parce qu'un constructeur global dans une autre unité de compilation peut changer global ) Par conséquent, ses effets secondaires doivent être préservés.

0 votes

Bien que j'accepte votre explication, il s'agit peut-être en fait d'un défaut, ou du moins d'une ambiguïté dans la norme que les gars de GCC ont compris. dcl.constexpr/7 stipule "...même résultat que non-constexpr...sauf qu'il peut apparaître dans une expression constante" . Maintenant, Foo(false) évidemment ne peut apparaissent dans une expression constante, donc... c'est peut-être pour cela.

0 votes

Pourriez-vous expliquer ce qui est censé se passer dans l'exemple de l'OP, dans un charabia non standardisé ? J'ai tendance à dire que ce que nous avons ici est avant tout un bogue dans la spécification mais pas de la rendre illégale. Mais peut-être n'ai-je pas compris constexpr suffisamment bien.

3voto

Lorehead Points 953

J'ajouterai que dcl.constexpr/5 requiert en plus :

Pour une fonction constexpr ou un constructeur constexpr qui n'est ni par défaut ni un modèle, s'il n'existe aucune valeur d'argument telle qu'une invocation de la fonction ou du constructeur puisse être une sous-expression évaluée d'une expression constante de base ou, pour un constructeur, un initialisateur constant pour un objet ([basic.start.static]), le programme est mal formé, aucun diagnostic n'est requis.

Puisque vous avez délibérément écrit la fonction de manière à ce que Foo(true) s'évalue à une expression constante de base, Foo(false) n'est pas tenu de le faire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X