Inspecter le membre inactif d'une union avec une séquence initiale commune dans l'expression constexpr
La norme C ++ au point 12.3.1 dit:
Si une union de mise en page standard contient plusieurs structures de mise en page standard qui partagent une séquence initiale commune, et si un membre de données non statique d'un objet de ce type d'union de mise en page standard est actif et fait partie des structures de mise en page standard, il est autorisé à inspecter la séquence initiale commune de n'importe lequel des membres de structure de mise en page standard;
Cependant, le code suivant ne se compile sur aucun compilateur majeur (https://godbolt.org/z/3jM1co):
struct type {
union {
int a;
int b;
};
constexpr type(int n) : a(n) {}
};
constexpr int fun(int n) {
type t(n);
return t.b;
}
constexpr int res = fun(5);
Pourquoi le code ne se compile pas (je crois que tous les compilateurs ne se trompent pas ici)? Ce code doit remplir les conditions d'accès au membre techniquement inactif d'un syndicat (mise en page standard, séquence initiale commune). Lorsque le constexprmot clé est supprimé, ce code se compile sans problème.
Réponses
Le texte que vous avez cité est correct, mais il existe des contraintes supplémentaires sur l'accès à un membre inactif d'une union dans un contexte constexpr. En particulier, vous enfreignez cette règle :
Une expression E est une expression constante de base à moins que l'évaluation de E, suivant les règles de la machine abstraite ([intro.execution]), évalue l'un des éléments suivants:
une conversion de lvaleur en rvalue qui est appliquée à une glvalue qui fait référence à un membre non actif d'une union ou à un sous-objet de celle-ci;
Notez que vous pouvez modifier le membre actif d'une union dans un contexte constexpr, vous pouvez donc le faire:
constexpr int fun(int n)
{
type t(n);
t.b = t.a; // t.b is now the active member
return t.b; // ok, reading from active member is fine
}
Je crois que cela n'est autorisé qu'à partir de c ++ 20: demo .
La règle pertinente est la suivante:
Une expression E est une expression constante de base à moins que l'évaluation de E, suivant les règles de la machine abstraite ([intro.execution]), évalue l'un des éléments suivants:
une invocation d'un constructeur de copie / déplacement défini implicitement ou d'un opérateur d'affectation de copie / déplacement pour une union dont le membre actif (le cas échéant) est mutable, à moins que la durée de vie de l'objet union ait commencé dans l'évaluation de E ;
(je souligne). Puisque la durée de vie de tcommence à l'intérieur de l'évaluation de fun, cela est autorisé.