void foo(int)
{
}
class X
{
void foo()
{
}
void bar()
{
foo(42);
// error: no matching function for call to 'X::foo(int)'
// note: candidate is:
// note: void X::foo()
// note: candidate expects 0 arguments, 1 provided
}
};
为什么C ++无法调用自由函数(这是唯一具有正确签名的函数)?
答案 0 :(得分:12)
因为两个标识符在不同的范围内定义,并且重载解析仅涉及同一范围内的函数。一旦编译器发现该类具有foo
,它就会停止攀升到更宽的范围(C ++11§3.4.1/ 1),因此隐藏了自由函数foo
。
您需要使用限定名称来引用全局foo
:
::foo(42);
答案 1 :(得分:5)
合乎逻辑的原因是一致性。
foo(42)
解析为
::foo(int)
。X::foo()
更改为X::foo(int)
,那么
foo(42)
将被解析为X::foo(int)
。哪个不一致。这也是派生类函数在有相似名称时隐藏基类函数的原因。
此类案件可以通过两种方式解决;
(1)提供完全限定名称(例如::foo(42)
)
(2)使用using
实用程序; e.g。
void bar()
{
using ::foo;
foo(42);
}
答案 2 :(得分:2)
内部作用域中的名称隐藏外部作用域中的名称。无论是函数还是其他东西,或者你是在类或名称空间中都没关系。
只有当名称查找找到多个具有相同名称的函数时,重载决策才会尝试选择与该调用最匹配的那个。
答案 3 :(得分:1)
真的很喜欢你的问题。我也可以说,使用这种语法:
::foo(42);
但我可以说,在我看来,它更优雅,编程更好,设置名称空间,所以你可以这样写:
namespace MyNameSpace
{
void foo(int){}
class X
{
void foo(){}
void bar()
{
MyNameSpace::foo(42);
}
};
};
这是一件好事,因为Namespaces
允许在名称下对类,对象和函数进行分组。
PS:然后,当您没有任何名称空间时,这可以帮助您理解写::foo(42);
的含义。
答案 4 :(得分:0)
我无法回答你问题的部分原因 - 我不知道语言规范背后的理由是什么。
要在示例中调用全局函数,请使用:: syntax:
::foo(42);
答案 5 :(得分:0)
原因是编译器首先查找匹配的函数名,忽略返回值和参数。当在一个类中时,它将尝试在那里寻找匹配的成员(实际上,它将查看所有“向上”的作用域;本地作用域,函数作用域,类作用域,命名空间作用域,全局作用域等。 )。
X::foo
是第一个匹配的名称。然后(不是之前)它会尝试根据参数选择正确的重载(如果有多个声明)(这是你可以用不同的参数重载相同的函数但只有不同的返回值的原因)然后它会检查返回值(如果有的话)。