Ich habe vor kurzem eine Frage hier gestellt (Detecting instance method constexpr with SFINAE), wo ich versuchte, einige Competexpr-Erkennung zur Kompilierzeit zu tun. Irgendwann habe ich herausgefunden, dass man noexcept
dazu ausnutzen kann: jeder konstante Ausdruck ist auch noexcept
. Also habe ich die folgenden Maschinen zusammen:Constexpr declltype
template <class T>
constexpr int maybe_noexcept(T && t) { return 0; }
...
constexpr bool b = noexcept(maybe_noexcept(int{}));
Dies funktioniert und b
ist wahr, wie man erwarten würde, als Null-Initialisierung ein int
ist ein konstanter Ausdruck. Es gibt auch korrekt Null wenn es sollte (wenn ich int
zu einem anderen geeigneten Typ ändern).
Als nächstes wollte ich überprüfen, ob etwas constexpr
Move Constructible ist. Also tat ich dies:
constexpr bool b = noexcept(maybe_noexcept(int(int{})));
Und wieder funktioniert dies richtig für int
oder ein benutzerdefinierter Typ. Dies überprüft jedoch, ob der Typ sowohl einen consExpr-Standardkonstruktor als auch einen constexpr-Move-Konstruktor hat. Also, um dies zu umgehen, habe ich versucht zu declval zu ändern:
constexpr bool b = noexcept(maybe_noexcept(int(declval<int>())));
Dies führt zu b
falsch in gcc 5.3.0 zu sein (kann nicht klappern für irgendetwas davon verwenden, da klappert nicht richtig konstant machen Ausdrücke noexcept
). Kein Problem, sage ich, muss sein, denn declval
ist (interessanterweise) nicht markiert constexpr
. Also schreibe ich meine eigene naive Version:
template <class T>
constexpr T&& constexpr_declval() noexcept;
Ja, das ist naiv im Vergleich zu, wie die Standard-Bibliothek tut es, wie es auf Leere und wahrscheinlich andere Dinge zu ersticken, aber es ist jetzt in Ordnung. Also versuche ich wieder:
constexpr bool b = noexcept(maybe_noexcept(int(constexpr_declval<int>())));
Diese immer noch nicht funktioniert, ist b
immer falsch. Warum wird dies nicht als konstanter Ausdruck angesehen? Ist das ein Compiler Bug, oder verstehe ich nicht grundlegend über constexpr
? Es scheint, als ob es eine seltsame Interaktion zwischen constexpr
und nicht evaluierten Kontexten gibt.
@Cameron Der zweite Teil von dem, was Sie gesagt haben, ist sicherlich wahr, aber das erste technisch ist nicht. Jeder konstante Ausdruck * ist * "noexcept", das ist es nicht. Die Rückgabe einer "constexpr" -Funktion ist jedoch nicht immer ein konstanter Ausdruck. –
Ihr Funktionsaufruf ist kein konstanter Ausdruck, weil er undefiniert ist ([expr.const] /2.3) – 0x499602D2