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.
#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;
}
#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;
}