Verwirrung über konstante Ausdrücke

Dies ist eine Art Follow-up fürdieses Thema und befasst sich über einen kleinen Teil davon. Angenommen, unser Compiler hat wie im vorherigen Themaconstexpr Funktionen fürstd::initializer_list undstd::array. Gehen wir jetzt gleich zur Sache.

Das funktioniert:

#include <array>
#include <initializer_list>

int main()
{
    constexpr std::array<int, 3> a = {{ 1, 2, 3 }};
    constexpr int a0 = a[0];
    constexpr int a1 = a[1];
    constexpr int a2 = a[2];
    constexpr std::initializer_list<int> b = { a0, a1, a2 };

    return 0;
}

Das tut nicht:

#include <array>
#include <initializer_list>

int main()
{
    constexpr std::array<int, 3> a = {{ 1, 2, 3 }};
    constexpr std::initializer_list<int> b = { a[0], a[1], a[2] };

    return 0;
}

Es stürzt mit diesem Fehler ab:

error: 'const std::initializer_list<int>{((const int*)(&<anonymous>)), 3u}' is not a constant expression

Obwohl ich ein paar Zeitungen darüber gelesen habeconstexpr und konstante Ausdrücke mittlerweile macht dieses Verhalten für mich immer noch keinen Sinn. Wie kommt es, dass das erste Beispiel als gültiger konstanter Ausdruck betrachtet wird und nicht das zweite? Ich würde jede Erklärung begrüßen, damit ich mich danach in Ruhe ausruhen kann.

HINWEIS: Ich werde es gleich präzisieren, Clang wird das erste Snippet nicht kompilieren können, da es das nicht implementiertconstexpr Bibliothekserweiterungen, die für C ++ 14 geplant sind. Ich habe GCC 4.7 benutzt.

BEARBEITEN: Ok, hier ist das große Beispiel, das zeigt, was abgelehnt wird und was nicht:

#include <array>
#include <initializer_list>

constexpr int foo = 42;
constexpr int bar() { return foo; }
struct eggs { int a, b; };

int main()
{
    constexpr std::array<int, 3> a = {{ 1, 2, 3 }};
    constexpr int a0 = a[0];
    constexpr int a1 = a[1];
    constexpr int a2 = a[2];

    // From Xeo and Andy tests
    constexpr std::array<int, 1> a = { bar() }; // OK
    constexpr std::array<int, 3> b = {{ a[0], a[1], a[2] }}; // OK
    std::initializer_list<int> b = { a[0], a[1], a[2] }; // OK
    constexpr std::initializer_list<int> b = { a0, a1, a2 }; // OK
    constexpr std::initializer_list<int> b = { foo }; // OK
    constexpr std::initializer_list<int> c = { bar() }; // ERROR
    constexpr std::initializer_list<int> b = { a[0], a[1], a[2] }; // ERROR

    // From Matheus Izvekov and Daniel Krügler
    constexpr eggs good = { 1, 2 }; // OK
    constexpr std::initializer_list<eggs> bad = { { 1, 2 }, { 3, 4 } }; // ERROR
    constexpr std::initializer_list<eggs> bad2 = { good, good }; // ERROR

    return 0;
}

Antworten auf die Frage(2)

Ihre Antwort auf die Frage