web-dev-qa-db-fra.com

Modification d'une variable globale dans une fonction constexpr en C ++ 17

En C++ 17, êtes-vous autorisé à modifier des variables globales dans une fonction constexpr?

#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'attendrais pas à ce que vous le puissiez, mais le clang 6 le permet: https://godbolt.org/g/UB8iK2

GCC, cependant, ne fait pas: https://godbolt.org/g/ykAJMA

Quel compilateur est correct?

36
Drew

Quel compilateur est correct?

Clang a raison.

La définition d'une fonction constexpr selon dcl.constexpr/

La définition d'une fonction constexpr doit satisfaire aux exigences suivantes:

(3.1) son type de retour doit être un type littéral;
(3.2) chacun de ses types de paramètres doit être un type littéral;
(3.3) son corps de fonction doit être = delete, = default, Ou une instruction composée qui ne pas contiennent:

(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 durée de stockage du thread ou pour laquelle aucune initialisation est effectuée.

Aussi selon dcl.constexpr/5 :

Pour une fonction constexpr ou un constructeur constexpr qui n'est ni par défaut ni un modèle, si aucune valeur d'argument n'existe telle qu'une invocation de la fonction ou du constructeur pourrait être une sous-expression évaluée d'une expression constante de base,

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

De plus, Foo(false) pourrait l'être mais il n'est pas nécessaire que la constante soit évaluée.

[~ # ~] conclusion [~ # ~]

Ainsi, un bug dans GCC.


20
Joseph D.

J'ajouterai que dcl.constexpr/5 nécessite en outre:

Pour une fonction constexpr ou un constructeur constexpr qui n'est ni un modèle 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 pourrait être une sous-expression évaluée d'une expression constante de base ou, pour un constructeur, un initialiseur constant pour un objet ([basic.start.static]), le programme est mal formé, aucun diagnostic requis.

Étant donné que vous avez délibérément écrit la fonction afin que Foo(true) soit évaluée en une expression constante de base, Foo(false) n'est pas requis pour.

3
Davislor