Ist das gültiges C ++?
int main() {
constexpr auto sz = __func__ - __func__;
return sz;
}
GCC und MSVC denken, dass es in Ordnung ist, Clang denkt, dass es nicht: Compiler Explorer .
Alle Compiler sind sich einig, dass dies in Ordnung ist: Compiler Explorer .
int main() {
constexpr auto p = __func__;
constexpr auto p2 = p;
constexpr auto sz = p2 - p;
return sz;
}
Clang mag dieses wieder nicht, aber die anderen sind damit einverstanden: Compiler Explorer
int main() {
constexpr auto p = __func__;
constexpr auto p2 = __func__;
constexpr auto sz = p2 - p;
return sz;
}
Was ist hier oben? Ich denke, Arithmetik für nicht verwandte Zeiger ist undefiniertes Verhalten, __func__
gibt aber den gleichen Zeiger zurück, nein? Ich bin mir nicht sicher, also dachte ich, ich könnte es testen. Wenn ich mich richtig erinnere, std::equal_to
können nicht verwandte Zeiger ohne undefiniertes Verhalten verglichen werden:
#include <functional>
int main() {
constexpr std::equal_to<const char*> eq{};
static_assert(eq(__func__, __func__));
}
Clang denkt, dass dies eq(__func__, __func__)
kein konstanter Ausdruck ist, obwohl er std::equal_to::operator()
constexpr ist . Andere Compiler beschweren sich nicht: Compiler Explorer
Clang wird diesen auch nicht kompilieren. Beschwert sich, dass dies __func__ == __func__
kein konstanter Ausdruck ist: Compiler Explorer
int main() {
static_assert(__func__ == __func__);
}
__func__
ist als-obstatic const char __func__[] = "function-name";
und gleichwertig akzeptiert Demo ...__func__
und diese im static_assert verwenden ...__func__
vollständig aus der Constexpr-Bewertung entfernt wird.Antworten:
__func__
in C ++ ist ein Bezeichner. Insbesondere verweist es auf ein bestimmtes Objekt. Aus [dcl.fct.def.general] / 8 :Als funktionslokale vordefinierte Variable erscheint diese Definition (als ob) am Anfang des Funktionsblocks. Daher
__func__
bezieht sich jede Verwendung innerhalb dieses Blocks auf diese Variable.Für den Teil "jedes andere Objekt" definiert eine Variable ein Objekt.
__func__
benennt das von dieser Variablen definierte Objekt. Daher haben innerhalb einer Funktion alle Verwendungen des__func__
Namens dieselbe Variable. Undefiniert ist, ob diese Variable ein anderes Objekt als andere Objekte ist.Das heißt, wenn Sie sich in einer Funktion mit dem Namen befinden
foo
und das Literal an einer"foo"
anderen Stelle im Problem verwendet haben, ist es für eine Implementierung nicht verboten, dass die Variable__func__
auch dasselbe Objekt ist, das das Literal"foo"
zurückgibt. Das heißt, der Standard verlangt nicht, dass jede Funktion, in der sie__func__
angezeigt wird, Daten getrennt vom Zeichenfolgenliteral selbst speichern muss.Die "Als ob" -Regel von C ++ erlaubt es Implementierungen, davon abzuweichen, aber sie können dies nicht auf eine Weise tun, die erkennbar wäre. Während die Variable selbst möglicherweise eine andere Adresse als andere Objekte hat oder nicht, müssen sich Verwendungen
__func__
in derselben Funktion so verhalten, als würden sie sich auf dasselbe Objekt beziehen.Clang scheint
__func__
diesen Weg nicht umzusetzen . Es scheint so zu implementieren, als hätte es ein prvalue-String-Literal des Funktionsnamens zurückgegeben. Zwei unterschiedliche Zeichenfolgenliterale müssen sich nicht auf dasselbe Objekt beziehen, daher ist das Subtrahieren von Zeigern auf sie UB. Und undefiniertes Verhalten in einem Kontext mit konstantem Ausdruck ist schlecht geformt.Das einzige, was mich zögern lässt zu sagen, dass Clang hier zu 100% falsch ist, ist [temp.arg.nontype] / 2 :
Sehen Sie, dies scheint ein gewisses Durcheinander bei der Implementierung zu ermöglichen. Das heißt, obwohl
__func__
dies technisch gesehen ein konstanter Ausdruck sein kann, können Sie ihn nicht in einem Vorlagenparameter verwenden. Es wird wie ein String-Literal behandelt, obwohl es technisch gesehen eine Variable ist.In gewisser Hinsicht würde ich sagen, dass der Standard von beiden Seiten seines Mundes spricht.
quelle
__func__
kann das also in allen Fällen meiner Frage ein ständiger Ausdruck sein, oder? Der Code sollte also kompiliert sein.__func__
der Adresse mit dem eines anderen Objekts identisch ist und das zweite__func__
nicht? Zugegeben, das bedeutet nicht, dass sich die Adresse zwischen den beiden Instanzen unterscheidet, aber ich bin immer noch verwirrt!__func__
ist kein Makro; Es ist ein Bezeichner, der eine bestimmte Variable und damit ein bestimmtes Objekt benennt. Daher sollte jede Verwendung__func__
in derselben Funktion zu einem Wert führen, der sich auf dasselbe Objekt bezieht. Oder genauer gesagt, es kann nicht so implementiert werden, dass dies nicht der Fall wäre.new
, wird es erst dann ausgeführt, wenn das Programm endet.