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?

Artikash sagt Reinstate Monica
quelle

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 .

Barry
quelle
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(&)()>>);
0x5453
quelle