为什么 int 对象和函数类型之间不明确?
Why is it ambiguous between an int object and a function type?
下面是代码示例:
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++标准 (N4659 [basic.lookup]/1) 中找到:
名称查找将名称的使用与该名称的一组声明相关联。通过名称查找找到的声明应全部声明同一实体或全部声明函数;在后一种情况下,声明被称为形成一组重载函数。
查找用于函数调用的非限定名称有两个阶段:
- 名称的非限定查找
- 名称的参数相关查找。
非限定名称查找规则即使在查找用于函数调用的名称时,也会查找该名称的任何声明。(规则不是它只搜索该名称的函数声明)。 此阶段查找::k
和::A::k
,无论它们是函数、int
s还是其他什么。
依赖于参数的查找确实有一个规则,即只为查找的该部分找到函数声明。但这与此代码无关。
using
指令的相关行为由 [basic.lookup.unqual]/2 涵盖(由我编辑以显示与此问题相关的部分):
出于非限定名称查找规则的目的,由 using-指令指定的命名空间中的声明被视为该封闭命名空间的成员。
这澄清了using namespace A;
实际上并没有将A
的成员引入main()
的范围;但这意味着当在全局命名空间中查找名称时(因为它是 using 声明站点的最内层封闭命名空间),来自A
的名称也将在那里找到。
有三种方法可以解决歧义:
第一:
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 2017projectschemlabchemlabmain.cpp(17): error C2872: 'k': ambiguous symbol
1>c:...visual studio 2017projectschemlabchemlabmain.cpp(8): note: could be 'void k(int,int)'
1>c:...visual studio 2017projectschemlabchemlabmain.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
。由于您都可见,因此现在在查找表中有 2 个标识符或符号,名为k
。当你打电话给k(1, 1)
时,它不知道你打算选择哪一个。
这与这样做没有什么不同:
主.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
视为same scope
中declared
。它们以前是在自己的范围内声明的。变量k
在::A::k
中,函数void k(int,int){}
在::k(int,int){}
中。在 main 函数中,当您应用using namespace A;
这里发生的事情时,它需要every symbol
after
A::
,并且它会像在global
::
scope
中一样移动它以获得可见性。现在编译器必须对可用的符号做出选择,并看到我有一个k
和一个k
。你是说int k(){}
还是void k(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;
}
- Visual C++(VS2017)中用户定义的转换不明确
- 重载类方法的不明确调用
- 为函数定义符号不明确的指针参数
- 父类的私有函数会导致对具有相同名称和相似参数的子类中的公共函数的不明确调用
- 在 C++17 中的命名空间和子命名空间中重载运算符是不明确的
- C++ 编译器错误:P1LinkedList.cpp:145:错误:重载的"to_string(int&)"调用不明确
- 对重载函数find_first_not_of的不明确调用
- 不明确的成员模板查找
- gcc出现不明确的模板实例化错误
- 调用'Node'构造函数是不明确的
- 如何解决不明确的运算符过载问题?
- 使用 nullptr 调用重载方法是不明确的
- "+=" 操作在类型之间不起作用 std::复杂<double>和__complex__双精度
- "fpclassify":对重载函数的不明确调用
- 对"列表"的引用不明确,包括头文件
- 删除全局隐式函数 - 避免使用不明确的运算符
- 为什么 int 对象和函数类型之间不明确?
- Clang和GCC中不明确基类转换之间的行为差异
- 2013和GCC之间的全局函数和不明确的参数NULL与char*
- 列表和字符串之间的不明确构造函数<string>