Ist der folgende Code legitim?
template <int N>
class foo {
public:
constexpr foo()
{
for (int i = 0; i < N; ++i) {
v_[i] = i;
}
}
private:
int v_[N];
};
constexpr foo<5> bar;
Clang akzeptiert es, aber GCC und MSVC lehnen es ab.
Der Fehler von GCC ist:
main.cpp:15:18: error: 'constexpr foo<N>::foo() [with int N = 5]' called in a constant expression
15 | constexpr foo<5> bar;
| ^~~
main.cpp:4:15: note: 'constexpr foo<N>::foo() [with int N = 5]' is not usable as a 'constexpr' function because:
4 | constexpr foo()
| ^~~
main.cpp:4:15: error: member 'foo<5>::v_' must be initialized by mem-initializer in 'constexpr' constructor
main.cpp:12:9: note: declared here
12 | int v_[N];
| ^~
Wenn diese Art von Code in Ordnung wäre, könnte ich einige Verwendungen von index_sequence
s abschneiden .
_v
in der Initialisierungsliste bis C ++ 17 initialisiert werden sollte. Vielleicht hat sich in C ++ 20 etwas geändert.int
Mitglied haben niemals ein undefiniertes Verhalten ". Ich frage mich, ob GCC dies nicht konform ist oder umgekehrt ...Antworten:
Die triviale Standardinitialisierung war in einem
constexpr
Kontext bis C ++ 20 verboten .Ich vermute, der Grund ist, dass es leicht ist, "versehentlich" aus standardmäßig initialisierten Grundelementen zu lesen, eine Handlung, die Ihrem Programm undefiniertes Verhalten verleiht, und Ausdrücke mit undefiniertem Verhalten sind direkt verboten
constexpr
( ref ). Die Sprache wurde jedoch erweitert, sodass ein Compiler nun prüfen muss, ob ein solcher Lesevorgang stattfindet, und falls dies nicht der Fall ist, sollte die Standardinitialisierung akzeptiert werden. Es ist ein bisschen mehr Arbeit für den Compiler, aber (wie Sie gesehen haben!) Hat erhebliche Vorteile für den Programmierer.Seit C ++ 20 ist es legal,
v_
"nicht initialisiert" zu lassen, wie Sie es getan haben. Dann haben Sie alle seine Elementwerte zugewiesen, was großartig ist.quelle
constexpr
und den verknüpften Vorschlag überflogen;)