Por que remove_reference não funciona em funções?

38

Ocorreu algo estranho ao fazer algum modelo de metaprogramação no outro dia. Basicamente, tudo se resume a essa afirmação que não (como eu esperaria) passar.

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

No começo, pensei que estava cometendo um erro sintático ao definir uma referência de função, mas essa afirmação passa, mostrando que esse não é o caso.

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

Também tentei remove_referenceme implementar copiando a fonte da cppreference, mas isso também não funcionou. O que está acontecendo aqui?

Artikash diz Restabelecer Monica
fonte

Respostas:

42

Bem-vindo ao mundo dos tipos de funções abomináveis.

void() &não é uma referência a void(). A maneira de se escrever isso void(&)()(que, se você remove_reference_t, você retornaria void()- ou seja remove_reference_t , funciona em referências a funções, se o que você fornecer for realmente uma referência ao tipo de função).

O que void() &realmente se refere é o tipo de uma função membro qualificada para referência depois que você tira a classe. Isso é:

struct C {
    void f() &;
};

O tipo de &C::fé void (C::*)() &. Mas todos os ponteiros para os membros podem ser escritos como T C::*para algum tipo Te, nesse caso, o tipo Tseria void() &.

Veja também P0172 .

Barry
fonte
3
Alguém deve criar uma pergunta canônica para tipos de funções abomináveis.
22719 Brian
Uau, o C ++ nunca deixa de me surpreender, mesmo que eu o tenha aprendido e usado por quase 10 anos.
Kelvin Hu
13

O tipo que você possui não é uma referência a uma função, mas uma função com um qualificador de referência .

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
fonte