2014-02-16 5 views
17

Ist das folgende C++ 14/C++ 1y-Programm gemäß dem aktuellen Entwurf schlecht formatiert?C++ 1y/C++ 14: Zuweisung zu einem Objekt außerhalb seiner Lebensdauer ist in einem konstanten Ausdruck nicht erlaubt?

#include <cstddef> 

template<typename T, size_t n> 
struct literal_array 
{ 
    T data[n]; 
}; 

template<typename T, size_t n, size_t m> 
constexpr literal_array<T, n+m> operator+(literal_array<T, n> a, 
              literal_array<T, m> b) 
{ 
    literal_array<T, n+m> x; 

    for (size_t i = 0; i < n; i++) 
     x.data[i] = a.data[i]; 

    for (size_t i = 0; i < m; i++) 
     x.data[n+i] = b.data[i]; 

    return x; 
} 

int main() 
{ 
    constexpr literal_array<int, 3> a = { 1, 2, 3 }; 
    constexpr literal_array<int, 2> b = { 4, 5 }; 

    constexpr auto c = a + b; 
} 

Clang Stamm (zum Zeitpunkt des Schreibens) ergibt:

error: constexpr variable 'c' must be initialized by a constant expression 
     constexpr auto c = a + b; 
        ^ ~~~~~ 
assignment to object outside its lifetime is not allowed in a constant expression 
       x.data[i] = a.data[i]; 
         ^
in call to 'operator+({{1, 2, 3}}, {{4, 5}})' 
     constexpr auto c = a + b; 
         ^

Was es bedeutet, "Zuordnung außerhalb seiner gesamten Lebensdauer Objekt"? Die Lebensdauer von x und seinen Unterobjekten schließt die Funktion ein, worum geht es also?

+0

Wenn wir das Problem vereinfachen, indem wir die Funktion nicht-Vorlage machen, macht die Fehlermeldung mehr Sinn, siehe [live] (http://coliru.stacked-crooked.com/a/a13b63215578d063). –

+0

Ich habe einen Fehlerbericht eingereicht und er erhielt eine Antwort, siehe meine aktualisierte Antwort. –

Antwort

10

Das Programm ist schlecht gebildet, weil Sie nicht initialisieren x, wenn Sie die Definition ändern:

literal_array<T, n+m> x = {{0}}; 

clang nicht mehr beschwert und es kompiliert ohne Fehler. Eine andere Lösung wäre, consExpr consrtuctors zu erstellen.

Wir können dies im draft standard Abschnitt finden 7.1.5Der constexpr Spezifizierer Absatz die sagt:

Die Definition einer constexpr Funktion stellt folgende Bedingungen erfüllen:

und schließt folgendes ein:

seine funktionsKörper wird = delete, = default oder eine Verbindung-Anweisung sein die nicht

enthält, die diese Kugel enthält (emphasis Mine):

eine Definition einer Variablen vom nicht-literalen Typ oder von statisch oder Thread Speicherdauer oder für die keine Initia lisierung wird durchgeführt.

und später wir das folgende Beispiel haben:

constexpr int uninit() { 
    int a; // error: variable is uninitialized 
    return a; 
} 

Die Beschwerde über die Lebensdauer von x nicht in der draft standard gegründet scheint. Der richtige Grund, soweit ich das beurteilen kann, sollte etwas in Richtung object is not initialized sein.Abschnitt 3.8Objekt Lebensdauer Absatz sein, die sagt

Der entsprechende Zitat aus dem Standard-Entwurf auf Objektlebensdauer würde:

Die Lebensdauer eines Objekts ist eine Runtime-Eigenschaft des Objekts. Ein Objekt soll nicht-triviale Initialisierung haben, wenn es eine Klasse oder Aggregattyp ist und es oder eines seiner Mitglieder von einem Konstruktor als einem trivialen Standardkonstruktor initialisiert wird. [Hinweis: Initialisierung durch eine triviale Kopie/Move-Konstruktor ist nicht-trivial Initialisierung. - Endnote] Die Lebensdauer eines Objekts des Typs T beginnt wenn:

  • Lagerung mit der richtigen Ausrichtung und Größe für den Typ T erhalten wird, und
  • , wenn das Objekt nicht-triviale Initialisierung, Die Initialisierung ist abgeschlossen.

Nur für den Fall fehlt Ich war etwas, das ich habe auch überprüft std::is_trivial mit:

std::cout << std::boolalpha << std::is_trivial<literal_array<int, 3>>::value << std::endl ; 

und das Ergebnis als in true erwartet.

aktualisieren

reichte ich eine bug report für dieses und die Antwort enthält diese Aussage:

[...] Das Problem ist, dass wir die implizite Regel noch nicht realisieren, dass solche Eine Funktion kann nicht in einem konstanten Ausdruck aufgerufen werden.

+0

Das Bit über die Lebensdauer ist ein bisschen seltsam, macht aber Sinn, wenn Sie vorgeben, dass die Initialisierung erforderlich ist, um die Lebensdauer eines 'literal_array' zu beginnen, wobei POD die Lebenszeit-Regeln gelockert hat. – Potatoswatter

+0

Wenn das, was du suchst, nicht in §3.8 [basic.life] ist, könntest du auf einer wilden Gänsehaut sein. Ich würde sagen, dass Clang einfach falsch ist, in diesem Fall etwas über das Leben zu sagen. – Potatoswatter

+3

Ihre Analyse ist richtig - Clang verwendet diese Diagnose, da das Objekt nicht initialisiert ist. Nicht initialisierte Objekte sollen nicht in 'conexpr'-Funktionen möglich sein, daher haben wir keine" uninitialisierte "Diagnose. Das Problem ist, dass wir den Aufruf von 'operator +' überhaupt nicht zulassen dürfen, weil 'x' nicht initialisiert wird. (Siehe auch die längere Erklärung, die ich in Ihrem Bericht über den Clang-Fehler hinterlassen habe.) –