Dlaczego remove_reference nie działa na funkcje?

38

Wpadłem na coś dziwnego podczas wykonywania metaprogramowania szablonu innego dnia. Zasadniczo sprowadza się do tego twierdzenia, że ​​nie jest (jak się spodziewałbym) przemijanie.

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

Na początku myślałem, że popełniam błąd składniowy, definiując odwołanie do funkcji, ale to twierdzenie mija, pokazując, że tak nie jest.

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

Próbowałem też zaimplementować remove_referencekopiowanie źródła z cppreference, ale to też nie działało. Co tu się dzieje?

Artikash mówi Przywróć Monikę
źródło

Odpowiedzi:

42

Witamy w świecie ohydnych typów funkcji.

void() &to nie nawiązanie do void(). Sposób, w jaki się pisze, że będzie void(&)()(co jeśli remove_reference_t, co można uzyskać z powrotem void()- to remove_reference_t robi prace nad odniesieniami do funkcji, jeśli to, co podać w rzeczywistości jest to odniesienie do rodzaju funkcji).

To, co void() &tak naprawdę dotyczy, to rodzaj funkcji członka kwalifikowanej do odwołania po usunięciu klasy. To jest:

struct C {
    void f() &;
};

Rodzaj &C::fjest void (C::*)() &. Ale wszystkie wskaźniki do członków mogą być zapisane jak T C::*dla pewnego typu T, w tym przypadku Tbyłby to typ void() &.

Zobacz także P0172 .

Barry
źródło
3
Ktoś powinien stworzyć pytanie kanoniczne dla ohydnych typów funkcji.
Brian
Wow, C ++ nigdy mnie nie zaskoczy, nawet jeśli się go nauczyłem i używam przez prawie 10 lat.
Kelvin Hu
13

Typ, który masz, nie jest odwołaniem do funkcji, ale funkcją z kwalifikatorem odwołania .

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
źródło