根据 cppreference 自 C++23 起
对于未使用 cv 限定符或 ref 限定符声明的非静态非虚拟成员函数,其第一个参数如果不是函数参数包,则可以是显式对象参数(用前缀关键字
表示) .this
这个参数可以是
void
类型吗?当前的编译器允许这样做,但在调用此类成员函数方面存在分歧:
struct A {
void f(this void) {}
};
// ok everywhere
auto p = &A::f;
int main() {
// ok in GCC and MSVC
p();
// ok in Clang
A{}.f();
}
Clang 用
拒绝
p();
错误:调用的对象类型“void (A::*)()”不是函数或函数指针
GCC 不喜欢
A{}.f();
因为
注意:候选人期望 -1 个参数,提供 0 个
以及 MSVC:
错误 C2660:'A::f':函数不接受 0 个参数
在线演示:https://gcc.godbolt.org/z/zMaqaTTav
这里哪个编译器是正确的?
就目前标准的编写方式而言,我倾向于认为 Clang 是行为正确的。
根据[dcl.fct]/3:
由非依赖类型 void 的单个未命名参数组成的参数列表相当于空参数列表。
this
关键字不会影响参数的类型,该参数仍然是void
并且保持未命名状态。由于它不在模板内,因此它也不依赖。
[dcl.fct] 的其余部分假设已对声明进行了此调整,但没有再次明确提及,例如在 [dcl.fct]/5 中定义函数的类型时。
因此我认为在this
调整之后还应该考虑在参数声明中指定
void
的效果以声明显式对象参数的[dcl.fct]/6。
然后,由于
this void
参数声明已从列表中删除,因此该函数不是显式对象函数,而是不带任何参数的隐式对象函数。
函数类型将为
void()
和 &A::f
然后形成 void (*A::f)()
类型的成员指针。使用函数调用语法 p()
调用成员指针是不可能的。
使用成员访问表达式
A{}.f()
调用非静态成员函数是可能的。函数定义中的this
将指向从A{}
具体化的临时对象。
但是,我不确定这是否真的是理想的行为。
void
参数例外仅存在于 C 向后兼容性。无需将其扩展为 this void
,无论如何,这在 C 中是无效的。相反,我认为它应该像(cv 限定的)void
参数的所有其他用途一样格式错误。