web-dev-qa-db-fra.com

Pourquoi remove_reference ne fonctionne-t-il pas sur les fonctions?

Ran dans quelque chose d'étrange lors de la métaprogrammation de modèle l'autre jour. Cela revient essentiellement à cette affirmation qui ne passe pas (comme je m'y attendais).

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

Au début, je pensais que je faisais une erreur syntaxique en définissant une référence de fonction, mais cette assertion passe, montrant que ce n'est pas le cas.

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

J'ai également essayé d'implémenter remove_reference moi-même en copiant la source depuis cppreference mais cela n'a pas fonctionné non plus. Qu'est-ce qui se passe ici?

Bienvenue dans le monde des types de fonctions abominables.

void() & n'est pas pas une référence à void(). La façon d'épeler ce serait void(&)() (qui si vous remove_reference_t, Vous récupéreriez void() - c'est-à-dire remove_reference_t fonctionne sur les références aux fonctions, si ce que vous fournissez est en fait une référence au type de fonction).

Ce à quoi void() & fait réellement référence est le type d'une fonction membre qualifiée de référence après avoir supprimé la classe. C'est:

struct C {
    void f() &;
};

Le type de &C::f Est void (C::*)() &. Mais tous les pointeurs vers les membres peuvent être écrits comme T C::* Pour certains types T, et dans ce cas, le type T serait void() &.

Voir aussi P0172 .

42
Barry

Le type que vous avez n'est pas une référence à une fonction, mais une fonction avec un qualificatif de référence .

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