以下是代码示例:
namespace A
{
int k;
}
void k(int,int){/*dosomething*/}
int main()
{
using namespace A;
k(1,1);//ooop!k is ambiguous!
}
发生什么事了?我认为它不应该是模糊的,因为它们是不同的类型。为什么它含糊不清?使用int k
时,无法执行k(1,1)
。
所以它与名称实际上没有任何关系?即使一个不是函数类型的名称也会在我们使用k(1,1)
时引起歧义,这在语法上是错误的,因为int k
不是功能?
答案 0 :(得分:10)
名称k
的查找不明确,因为有两个匹配的声明可见,::k
和::A::k
。
确切的规则可以在C ++标准(N4659 [basic.lookup] / 1)中找到:
名称查找将名称的使用与该名称的一组声明相关联。通过名称查找找到的声明应全部声明同一实体或全部声明功能;在后一种情况下,声明会形成一组重载函数。
查找用于函数调用的非限定名称有两个阶段:
非限定名称查找规则,即使在查找用于函数调用的名称时,也会查找该名称的任何声明。(规则并不是它只搜索函数声明那个名字)。此阶段同时找到::k
和::A::k
,无论这些是函数,int
还是其他。
依赖于参数的查找确实有一条规则,即只查找该部分查找的函数声明。但这与此代码无关。
using
指令的相关行为由[basic.lookup.unqual] / 2涵盖(由我编辑,只显示与此问题相关的部分):
出于非限定名称查找规则的目的,using-directive指定的命名空间中的声明被视为该封闭命名空间的成员。
这澄清了using namespace A;
实际上并未将A
的成员引入main()
的范围;但这意味着当在全局命名空间中查找名称时(因为这是使用声明的站点的最里面的封闭命名空间),也会在那里找到A
的名称。
答案 1 :(得分:2)
有三种方法可以解决歧义:
第一
int main() {
A::k = 5;
::k( 1, 1 );
}
第二
int main() {
using namespace A;
A::k = 5;
::k(1, 1);
}
第三
namespace A {
int k;
}
namespace B {
void k( int, int ) { /* do something */ }
}
int main() {
using namespace A or B but not both!
if A then k = 5; okay && k(1,1); error
if B then k(1, 1); okay && k = 5; error
if both again ambiguous unless A::k = 5; || B::k(1,1);
return 0;
}
由于歧义的性质,使用using namespace A
并不真正付出代价。这就是为什么在全局范围内或直接在主函数中使using namespace std;
被认为是不好的做法。只要不与任何其他库冲突,就可以在类/结构的函数或成员函数中使用它。
我在我的IDE Visual Studio 2017 CE中运行了这个,这是编译错误:
1>------ Build started: Project: ChemLab, Configuration: Debug Win32 ------
1>main.cpp
1>c:\...\visual studio 2017\projects\chemlab\chemlab\main.cpp(17): error C2872: 'k': ambiguous symbol
1>c:\...\visual studio 2017\projects\chemlab\chemlab\main.cpp(8): note: could be 'void k(int,int)'
1>c:\...\visual studio 2017\projects\chemlab\chemlab\main.cpp(6): note: or 'int A::k'
1>Done building project "ChemLab.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
使用using namespace directive
时,它会占用该命名空间中的所有内容并使其对main可见。所以现在在main中你可以在main中看到namespace A
和global namespace
。既然您已经可见,那么您现在在名为k
的查找表中有2个标识符或符号。当你致电k(1, 1)
时,它不知道你打算选择哪一个。
这与做到这一点没什么不同:
<强>的main.cpp 强>
#include <string>
class string {
public:
char* _chars;
};
int main() {
using namespace std;
string myString; // error ambiguous did you mean ::string or std::string?
return 0;
}
这可能会为您提供更多见解:
使用using directive
时,请不要将variable k
和function k
视为declared
中的same scope
。他们先前已在自己的范围内宣布。变量k
位于::A::k
,函数void k(int,int){}
位于::k(int,int){}
。在主要功能中,当你应用using namespace A;
这里发生的事情时,需要every symbol
after
A::
并且它会像global
中那样移动它::
scope
可见度。现在,编译器必须对可用符号做出选择,并看到我有一个k
和一个k
。您的意思是int k(){}
还是void k(int,int){}
...
答案 2 :(得分:-2)
模糊性来自名称。没有办法像函数/方法一样重载变量,因此名称中存在“冲突”。
为了得到你想要的“k”,你需要指定命名空间。
adb
或者,将名称空间排除在等式之外:
namespace A
{
int k;
}
void k(int, int) {/*dosomething*/ }
int main()
{
using namespace A;
::k(1, 1); // uses the global namespace
A::k = 5; // uses the namespace A
}