Warum funktioniert remove_reference nicht für Funktionen?


38

Ich bin neulich auf etwas Seltsames gestoßen, als ich eine Vorlagen-Metaprogrammierung durchgeführt habe. Es kommt im Grunde darauf an, dass diese Behauptung nicht (wie ich erwarten würde) vorübergeht.

static_assert(std::is_same_v<void(), std::remove_reference_t<void()&>>);

Zuerst dachte ich, ich hätte einen syntaktischen Fehler beim Definieren einer Funktionsreferenz gemacht, aber diese Behauptung ist erfolgreich und zeigt, dass dies nicht der Fall ist.

static_assert(std::is_same_v<void()&, void()&>);

Ich habe auch versucht, remove_referencemich selbst zu implementieren, indem ich die Quelle von cppreference kopiert habe, aber das hat auch nicht funktioniert. Was geht hier vor sich?

Antworten:


42

Willkommen in der Welt der abscheulichen Funktionstypen.

void() &ist kein Hinweis auf void(). Die Art und Weise buchstabieren , dass sein würde void(&)()(was , wenn Sie remove_reference_t, würden Sie wieder bekommen void()- das ist remove_reference_t tut Arbeit auf Verweise auf Funktionen, wenn das, was Sie bieten es ist eigentlich ein Verweis auf Funktionstyp).

Was sich void() &tatsächlich bezieht, ist der Typ einer referenzqualifizierten Elementfunktion, nachdem Sie die Klasse entfernt haben. Das ist:

struct C {
    void f() &;
};

Die Art von &C::fist void (C::*)() &. Aber alle Zeiger auf Elemente geschrieben werden können als T C::*für eine Art T, und in diesem Fall der Typ Twäre void() &.

Siehe auch P0172 .


3
Jemand sollte eine kanonische Frage für abscheuliche Funktionstypen erstellen.
— Brian

Wow, C ++ überrascht mich immer wieder, auch wenn ich es fast 10 Jahre lang gelernt und benutzt habe.
— Kelvin Hu

13

Der Typ, den Sie haben, ist keine Referenz auf eine Funktion, sondern eine Funktion mit einem Referenzqualifizierer .

static_assert(std::is_same_v<void()&, void()&>);
static_assert(!std::is_same_v<void()&, void(&)()>);
static_assert(std::is_same_v<void(&)(), void(&)()>);
static_assert(std::is_same_v<void(), std::remove_reference_t<void(&)()>>);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.