为什么remove_reference函数不能用于函数?

38
前几天在进行一些模板元编程时遇到了一些奇怪的问题。基本上就是这个断言没有通过(与我预期的不同)。
static_assert(std::is_same_v<void(), std::remove_reference_t<void()&>>);

起初我以为我在定义一个函数引用时犯了语法错误,但这个断言通过了,表明并非如此。
static_assert(std::is_same_v<void()&, void()&>);

我也尝试过自己实现remove_reference,从cppreference上复制了源代码,但也没有成功。这里到底发生了什么?
2个回答

43
欢迎来到可怕函数类型的世界。 void() & 不是对 void() 的引用。正确的写法应该是 void(&)()(如果你使用 remove_reference_t,你会得到 void() -- 也就是说,remove_reference_t 对于函数类型的引用是有效的,只要你提供的确实是函数类型的引用)。
实际上,void() & 是指类成员函数的限定符引用类型,去掉类名后就是这个意思:
struct C {
    void f() &;
};
&C::f 的类型为 void (C::*)() &。但是所有成员指针都可以用类似于 T C::* 的方式来表示,其中 T 表示某种类型,此时 T 的类型为 void() &
另请参见P0172

3
应该有人为可恶的函数类型创建一个规范问题。 - Brian Bi
哇,即使我已经学习和使用C++近10年,它仍然能够让我感到惊喜。 - Kelvin Hu
@KelvinHu 什么?那是C语言... 函数类型是 void (void)。函数指针是 void (*) (void)。而一些返回类型说明符会“爬过头部”并出现在参数列表之后。好老的K&R。所有这些C++添加的都是限定符和能够在成员函数中使用的能力:void (Class::*) (/*跳过void*/) /*const/ref-qualifier*/ - undefined

13

你拥有的类型不是对函数的引用,而是带有引用限定符的函数。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接