为什么调用与成员函数同名的非成员函数会产生错误
Why calling a non-member function with the same name as a member function generates an error
我有下一个代码:
void f(int){}
struct A
{
void f()
{
f(1);
}
};
此代码的格式不正确,错误消息(GCC):error: no matching function for call to ‘A::f(int)’
或(clang)Too many arguments to function call, expected 0, have 1; did you mean '::f'?
为什么我需要使用::
来调用与成员函数同名但签名不同的非成员函数?这个要求的动机是什么
我认为编译器应该能够弄清楚我想调用非成员函数,因为签名不同(clang甚至把它放在错误消息中!)。
请不要将其标记为重复-这与在C++中调用具有相同的方法的类内的非成员函数是不同的问题
为什么我需要使用::来调用与成员函数同名但签名不同的非成员函数
因为这些都是规则。嵌套作用域中的名称会在更大的作用域中隐藏具有相同名称的实体。
这个要求的动机是什么?
考虑一个成员函数调用另一个签名不完全匹配的成员的情况:
struct A {
void f(double);
void g() {f(42);} // requires int->double conversion
};
现在假设有人在周围的名称空间中添加了一个不相关的函数
void f(int);
如果这包含在A
范围内的一组重载中,那么A::g
的行为会突然发生变化:它会调用它而不是A::f
。将重载集限制为最窄可用范围内的名称可以防止这种意外的破坏。
正如你(和你乐于助人的编译器)所说,如果你需要,外部名称仍然可用(有资格)。
编译器对§3.4.1[basic.lookup.uqual]中指定的f
执行无资格名称查找(谢天谢地,这里没有ADL):
1在3.4.1.中列出的所有情况下,都会在范围中搜索按各个类别中列出的顺序进行申报;一旦找到名称的声明,名称查找就会结束。如果没有找到声明,程序格式错误。
8对于类
X
的成员,在成员函数中使用的名称body,在默认参数中,在异常规范中,在非静态数据成员(9.2)的brace或equal初始值设定项,或者在X的定义之外的类成员的定义中,在成员的声明符id之后,应在以下其中之一中声明以下方式:
- 在其使用的砌块或封闭砌块(6.3)中使用之前,或
- 应为
X
类成员或X
(10.2)基类成员,或- 如果
X
是类Y
(9.7)的嵌套类,则应是Y
的成员,或者应是Y
基类的成员(此查找适用依次转到Y
的封闭类,从最内层开始封闭类),或者- 如果
X
是局部类(9.8)或是局部类的嵌套类,则在包含定义的块中的类X
的定义之前X
类,或- 如果
X
是命名空间N
的成员,或者是属于N
成员的类的嵌套类,或者是本地类或中的嵌套类在使用之前,属于N
成员的函数的局部类名称,位于名称空间N
或N
的封闭名称空间之一中
一旦找到声明,名称查找就会停止。因此,一旦它在第二个项目符号处找到成员f()
,它就会停止并从不在其他地方搜索。
拒绝不可行的函数是在名称查找后,以过载分辨率完成的。
为什么我需要使用::来调用与成员函数同名但签名不同的非成员函数?这个要求的动机是什么?
这就是拥有名称空间的全部意义。与全局名称相比,本地(范围更近)名称更受欢迎,也更可见。由于struct
又是一个作用域,因此它的f
遮蔽了::f
的可见性。当你必须拥有全球性的时,你必须说你拥有。为什么?
这是作为一个功能提供的,以确保您可以和平地调用您定义的函数,假设它们会被调用,并且当您需要来自不同命名空间(比如标准库)的函数时,您可以明确声明,比如std::
。这只是一种纯粹的歧义消除形式,没有留下发挥作用的机会。
要了解错误的原因以及为什么需要显式使用::f()
语法,您可能需要考虑C++编译器过程的某些方面:
编译器所做的第一件事是名称查找。
不合格名称查找从当前范围开始,然后向外移动;一旦找到函数名称的声明,它就会停止,即使该函数稍后被确定为不是函数调用的可行候选函数。
然后,对名称查找找到的函数集执行重载解析。
(最后,访问检查是在过载解析获得的函数上执行的。)
- 如何使用指针传递给函数的数组中对象的函数成员
- c++构造函数成员初始化:传递参数
- 创建 std::函数,它返回具有函数成员值的变量.分段错误
- 如何在C++通过公共函数访问私有函数成员?
- 解释了构造函数成员初始化列表
- 调用std::函数成员时内存损坏
- 是否可以为模板类的模板函数成员设置别名?
- 捕获 lambda 函数C++成员变量
- 构造函数成员初始值设定项跨成员列出,安全吗?
- 获取与在模板参数中传递的函数成员类型相同的类
- 如何从公共函数成员访问地图私有成员
- C 构造函数成员分配优化
- 使用命名空间进行函数成员定义
- 函数成员作为 CUDA 内核的参数
- 模板基类函数成员的别名
- 函数成员中用于void和继承的enable_if
- 头文件中是否定义了一个很长的Class函数成员
- 类内/构造函数成员初始化
- 使用指向部分专用函数成员的指针自动填充向量
- 指向函数成员的指针