C++ 为什么编译器停止重载的名称查找?

C++ 为什么编译器停止重载的名称查找?,c++,compiler-construction,C++,Compiler Construction,我刚刚读到这篇文章: 作者在这里通过使用名称空间显示编译器在遇到第一个重载时停止查找重载 namespace A { void f(int x); // like our std::sqrt(double) } namespace B { struct S {}; // user-defined type with associated namespace B void f(S); void f(int, int); void test1() {

我刚刚读到这篇文章: 作者在这里通过使用名称空间显示编译器在遇到第一个重载时停止查找重载

namespace A
{
   void f(int x); // like our std::sqrt(double)
}

namespace B
{
   struct S {}; // user-defined type with associated namespace B

   void f(S);
   void f(int, int);

   void test1()
   {
      using namespace A; // using DIRECTIVE
      f(1);              // ERROR  namespace A is not considered because
                         //        B contains two overloads for 'f'
      f(1,2);            // OK     B::f(int,int)
      f(B::S());         // OK     B::f(S)
   }   

   void test2()
   {
      using A::f; // using DECLARATION
      f(1);       // OK     A::f(int)
      f(1,2);     // ERROR  A::f  hides  B::f(int,int)
      f(B::S());  // OK     B::f(S) due to ADL!
   }
}

namespace C
{
   void test3()
   {
      using namespace A; // using DIRECTIVE
      f(1);              // OK     A::f(int)
      f(B::S());         // OK     B::f(S) due to ADL!
   }   

   void test4()
   {
      using A::f; // using DECLARATION
      f(1);       // OK     A::f(int)
      f(B::S());  // OK     B::f(S) due to ADL!
   }
}
为什么编译器应该停止

编辑#1:问题确实是:标准为什么这么说


谢谢你的回答

使用A::f隐藏了“f”之前的所有定义

你可以使用

   void test2()
   {      
      f(1,2);     // ERROR  A::f  hides  B::f(int,int)
      using A::f; // using DECLARATION
      f(1);       // OK     A::f(int)
      f(B::S());  // OK     B::f(S) due to ADL!
   }

最好的做法是打电话

   void test2()
   {
       A::f(1);       // OK     A::f(int)
       B::f(1,2);     // ERROR  A::f  hides  B::f(int,int)
       B::f(B::S());  // OK     B::f(S) due to ADL!
   }
它明确提到使用哪个函数

当遇到第一个重载时,编译器停止查找重载

不,它不会在“遇到第一个时”停止,否则您无法同时找到
B::f(int,int)
B::f(S)

它查找给定范围内的所有重载(不仅仅是第一个重载),但不进一步查找更遥远的范围

< P>这就像C++中的所有名称查找,如果你有一个全局变量叫做“代码> var <代码>,在某些函数中你也有一个名为<代码> var >代码的本地变量,使用函数内的名称将引用局部变量。这样做更有用,因为您更可能打算使用在附近声明的变量,因为它在相关代码中


如果有人递给你一封信,告诉你把它交给弗雷德,他站在几米远的地方,身上戴着一枚写着“我是弗雷德”的徽章,你会不理他,走出去,继续寻找世界上所有其他叫弗雷德的人吗?

显而易见的答案是:因为标准是这么说的。原因 标准中这样说是为了使您的程序更加健壮: 假设您编写了您的类:

class MyClass : public SomeBase
{
private:
    void f( int );
    void g()
    {
        f( 'x' );
    }
};
目前,在
g
中的调用站点,编译器将找到
MyClass::f(int)
,并且只有
MyClass::f(int)
。那是 也许是你想要的。您不希望编译器 如果有人碰巧遇到了,突然开始查找
SomeBase::f(char)
加上它。(至少,理由是这样的。)

最后:编译器在运行时并不总是停止查找 查找一个符号。例如,需要考虑ADL。 模板中的规则略有不同,具体取决于
符号是否依赖。

因为标准如此规定?很好且易于理解的类比。但是我,作为一个新手程序员,实际上期望编译器完成一个完整的查找。直到我读了这篇博文。是否有一个编译器选项来发现这种情况,以便编译器可以警告我?或者更好,这种行为叫什么名字,这样我就可以用谷歌搜索它了。。。(名称查找?@0x499602D2,不,我会说名称查找。重载解析通常指确定几个命名函数中的哪一个最匹配,但必须先执行名称查找才能找到这些函数有时会说,内部作用域中的名称声明会掩盖外部作用域中的声明,而
SomeBase
也有这样的方法,然后我希望编译器选择更专业的方法->
MyClass::f(int)
class MyClass : public SomeBase
{
private:
    void f( int );
    void g()
    {
        f( 'x' );
    }
};