为什么编译器在重载时停止名称查找

Why does the compiler stops the name lookup on overloads?

本文关键字:查找 编译器 重载 为什么      更新时间:2023-10-16

我刚刚读了这篇文章:c++名称空间的乐趣在这里,作者通过使用命名空间表明编译器在遇到第一个重载时停止查找。

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:问题确实是:为什么标准这么说?

谢谢你的回答!

编译器在遇到第一个

时停止查找重载

不,当遇到第一个时,它不会停止" 否则你不能同时找到B::f(int,int)B::f(S)

查找给定作用域中的所有重载(不仅是第一个),但不会在更远的作用域中进一步查找。

这就像c++中的所有名称查找一样,如果你有一个全局变量var,在某些函数中你也有一个局部变量var,在函数中使用名称将引用局部变量。这样更有用,你更有可能使用在附近声明的变量,因为它在相关代码中。

如果有人递给你一封信,让你把它交给弗雷德,他站在几米远的地方,戴着一个徽章,上面写着"我是弗雷德",你会无视他,走到外面,继续寻找世界上其他叫弗雷德的人吗?

using 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()
   {
      using A::f; // using DECLARATION
      f(1);       // OK     A::f(int)
      using B::f;
      f(1,2);     // ERROR  A::f  hides  B::f(int,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!
   }

它明确地提到了使用哪个函数

显而易见的答案是:因为标准是这么说的。的原因标准说这样做是为了让你的程序更健壮:假设您已经编写了您的类:

class MyClass : public SomeBase
{
private:
    void f( int );
    void g()
    {
        f( 'x' );
    }
};

现在,在g的调用位置,编译器将找到MyClass::f(int),只有MyClass::f(int)。这是可能是你想要的。你不想要的是编译器突然开始寻找SomeBase::f(char),如果有人碰巧添加它。(至少基本原理是这样的。)

最后:编译器不总是停止查找当它找到一个符号。例如,ADL需要考虑在内。规则在模板中略有不同,取决于符号是否依赖