2015-12-21 10 views
15

Der erste Schnipsel kompiliert ohne Warnungen (live example):Warum werden diese Snippets von GCC anders behandelt?

constexpr operator int() { return i; } 

GCC warnt, dass b a VLA ist:

#include <iostream> 

struct A { 
    constexpr A(): i(5){} 
    constexpr operator int() { return 5; } 
    int i; 
}; 

int main() { 
    A a; 
    int b[a]{ 0, 1, 2, 3, 4 }; 
    std::cout << b[4] << '\n'; 
} 

nun durch Rücksendung i in dem Umwandlungsoperator (live example) Die oben Schnipsel verändern .

Für mich scheinen beide Varianten dem Absatz §5.19 [expr.const]/3 in C++ 14 zu entsprechen.

Antwort

17

Sie die Durchführung einer ltr Umwandlung auf i, aber für [expr.const]/(2.7) hier nicht verletzt werden, (2.7.3) anwendbar sein,

enter image description here

(2.7.1) betrifft vollständige Objekte, (2.7.2) spricht über String-Literale und (2.7.4) handelt von Objekten, deren Lebensdauer bei der Auswertung des Ausdrucks anfing - nicht anwendbar, da a der Deklaration b vorangestellt ist.

Definieren Sie a als constexpr und der Code ist konform.


Ein kleiner Nachtrag zu klären, was die Standard-sagt: Der Ausdruck in den Klammern ein umgebauter konstanter Ausdruck muss Typen std::size_t ([dcl.array]/1), die in [expr.const]/4 als

A umgewandelt definiert ist Konstanter Ausdruck vom TypT ist ein Ausdruck, der implizit in den Typ T konvertiert wird, wobei der konvertierte Ausdruck ein konstanter Ausdruck und [... Anforderungen, die erfüllt sind ...]

So wirklich, ist der Standard interessiert, ob oder nicht

constexpr std::size_t s = a; 

gültig wäre. Was es aus den oben genannten Gründen nicht ist, ein Unterobjekt eines zuvor definierten Objekts zu verwenden.

+0

Warum muss 'a' in diesem Fall eine Lvalue-to-rvalue-Konvertierung durchlaufen? Ich frage das, weil die Definition eines "konvertierten konstanten Ausdrucks" in §5.19/3 (N4140) anscheinend keine solche Umwandlung von "a" in der Deklaration "int b [a] {0, 1" erfordert , 2, 3, 4}; '. – Ayrosa

+0

@Ayrosa Nun, 'a' muss sich nie einem unterziehen, aber der Konvertierungsoperator muss aufgerufen werden, um ihn in' std :: size_t' umzuwandeln. ('a' ist ein konvertierter konstanter Ausdruck vom Typ' std :: size_t' innerhalb der Klammern) – Columbo

+1

Es hat eine Weile gedauert, bis ich wirklich begriff, was Sie in Ihrer Antwort gesagt und hervorgehoben haben.Auf jeden Fall ist es keine leichte Aufgabe, den Standard vollständig zu verstehen. Große Antwort (+1). – Ayrosa

4

Die Array-Größe muss eine Kompilierzeitkonstante sein, aber im zweiten Beispiel erfolgt die Initialisierung von A::i erst ab Laufzeit.

+0

'A :: A()' ist 'constexpr' obwohl ... – YSC

+0

@YSC Ja, aber die Variable' a' in der 'main' Funktion ist nicht. –

+1

Und * das * ist die echte Warnquelle, oder? – YSC

Verwandte Themen