为什么int对象和函数类型之间不明确?

时间:2018-03-16 02:05:58

标签: 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 k不是功能?

3 个答案:

答案 0 :(得分:10)

名称k的查找不明确,因为有两个匹配的声明可见,::k::A::k

确切的规则可以在C ++标准(N4659 [basic.lookup] / 1)中找到:

  

名称查找将名称的使用与该名称的一组声明相关联。通过名称查找找到的声明应全部声明同一实体或全部声明功能;在后一种情况下,声明会形成一组重载函数。

查找用于函数调用的非限定名称有两个阶段:

  1. 不合格的名称查询
  2. 依赖于参数的名称查找。
  3. 非限定名称查找规则,即使在查找用于函数调用的名称时,也会查找该名称的任何声明。(规则并不是它只搜索函数声明那个名字)。此阶段同时找到::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 Aglobal 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 kfunction 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
 }