C++ 为什么int对象和函数类型之间不明确?
下面是代码示例:C++ 为什么int对象和函数类型之间不明确?,c++,c++11,C++,C++11,下面是代码示例: 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
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
不是函数?查找名称k
是歧义的,因为有两个匹配的声明可见,::k
和::A::k
确切的规则可以在C++标准中找到(N469[Basic,LoopUp]):1 名称查找将名称的使用与该名称的一组声明相关联。通过名称查找找到的声明要么全部声明同一实体,要么全部声明函数;在后一种情况下,这些声明形成了一组重载函数
查找用于函数调用的非限定名称有两个阶段:
::k
和::A::k
,而不管它们是函数、int
s还是其他函数
依赖于参数的查找确实有一条规则,即仅为该部分查找找到函数声明。但这与本规范无关
[basic.lookup.unqual]/2涵盖了
using
指令的相关行为(由我编辑,仅显示与此问题相关的部分):
出于非限定名称查找规则的目的,using指令指定的命名空间中的声明被视为该封闭命名空间的成员
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
}
这澄清了
使用名称空间A
实际上并不将A
的成员引入main()
的范围;但这意味着在全局名称空间中查找名称时(因为这是使用声明的站点的最内层封闭名称空间),也会在那里找到a
中的名称。有三种方法来解决歧义:
第一:
第二:
第三:
由于模棱两可的性质,使用名称空间A
并不值得。这就是为什么使用名称空间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指令时,它将获取该名称空间中的所有内容,并使其对main可见。现在,在main中,您可以看到名称空间A
和全局名称空间
。由于两者都可见,现在在名为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;
}
#包括
类字符串{
公众:
char*_chars;
};
int main(){
使用名称空间std;
string myString;//错误不明确您的意思是::string还是std::string?
返回0;
}
这可能会为您提供更多的见解:
当使用using指令
时,不要认为变量k
和函数k
是在相同范围内声明的
。它们以前是在自己的范围内声明的。变量k
位于::A::k
中,函数void k(int,int){}
位于::k(int,int){}
中。在主函数中,当您使用命名空间A应用代码>这里发生的事情它需要每个符号在A::
之后,它会像在全局::
范围中一样移动它以获得可见性。现在,编译器必须对可用的符号进行选择,并看到我有一个k
和一个k
。你的意思是intk(){}
还是voidk(int,int){}
。歧义来自于名字。无法像重载函数/方法那样重载变量,因此名称中存在“冲突”
为了获得所需的“k”,需要指定名称空间
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
}
或者,将名称空间从等式中去掉:
void k(int, int) {/*dosomething*/ }
void k(int, int, float) {}
int main()
{
int k;
// all of these are now ambiguous
k(1, 1);
k(1, 2, 0.4);
k = 5;
}
k(int,int)
属于哪个名称空间?为使用k(1,1)
的块指定了哪个命名空间?名称空间A
是否有k(int,int)
?它是否有int k
?cppref的引用不适用,因为您没有在main
@BoPersson中声明任何名称。投票结果最高的答案是“在同一范围内找到了两个名称”,因此我引用这句话来证明“在sams范围内没有两个名称”。找到了两个名称,但是它们不在同一个范围内。@bigxiao-引文说的是“正在声明”,但主要没有声明任何内容。您可以在main中声明一个新的k
,这将隐藏另外两个。这就是引用的意思。但是等等!据我所知,using指令没有在范围中引入name@毕肖为什么不呢。这就是它的目的。@bigxiao它并没有阻止您声明同一个命名变量,但您并没有这样做,而是使用了name@NathanOliver我认为“两个名字在同一个范围内”
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
}
void k(int, int) {/*dosomething*/ }
void k(int, int, float) {}
int main()
{
int k;
// all of these are now ambiguous
k(1, 1);
k(1, 2, 0.4);
k = 5;
}