Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't remove_reference work on functions?

Ran into something strange when doing some template metaprogramming the other day. It basically comes down to this assertion not (as I would expect) passing.

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

At first I thought I was making a syntactic mistake defining a function reference, but this assertion passes, showing that's not the case.

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

I also tried implementing remove_reference myself copying the source from cppreference but that didn't work either. What is going on here?

like image 837
Artikash-Reinstate Monica Avatar asked Nov 15 '19 16:11

Artikash-Reinstate Monica


2 Answers

Welcome to the world of Abominable Function Types.

void() & is not a reference to void(). The way to spell that would be void(&)() (which if you remove_reference_t, you would get back void() -- that is remove_reference_t does work on references to functions, if what you provide it is actually a reference to function type).

What void() & actually refers to is the type of a reference-qualified member function after you strip off the class. That is:

struct C {
    void f() &;
};

The type of &C::f is void (C::*)() &. But all pointers to members can be written as T C::* for some type T, and in this case the type T would be void() &.

See also P0172.

like image 79
Barry Avatar answered Nov 07 '22 05:11

Barry


The type you have is not a reference to a function, but a function with a reference qualifier.

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(&)()>>);
like image 36
0x5453 Avatar answered Nov 07 '22 06:11

0x5453