C++ 命名空间的奇怪行为

8

这里有一些代码,显示了奇数:

namespace ns
{
  typedef int int_type;

  class classus {
    public: 
      int a = 0;
  };

  void print(classus c){
    printf("a equals %i \n", c.a);
  }
  void print(int_type a){
    printf("a equals %i \n", a);
  }
}

int main(int argc, char* argv[])
{
  ns::int_type a1 = 2;
  ns::classus a2;
  ns::print(a1); // this line wont work without explicit ns:: scope
  print(a2); // this line works with or without explicit ns:: scope
}

这可以在 Visual Studio 2017 上构建和运行。Intellisense 对其也非常满意。

似乎包含在命名空间中的类的变量会污染整个行,使其具有该命名空间的作用域。这是一个 bug 还是一个特性?无论哪种方式,是否有关于此的文档......还没有找到任何文档。


这也展示了禁用ADL的最简单方法:使用typedef从没有任何函数的命名空间导入类型。https://godbolt.org/z/PmmgZs - sudo rm -rf slash
1
@sudorm-rfslash,谢谢。当我看到你的例子时,我立刻想要摆脱“using”。这个怎么样:https://godbolt.org/z/fT7gVf - Stefan Karlsson
1个回答

9
你所困惑的特性称为ADL(argument dependent lookup)。
来自cppreference
引用: 参数依赖查找,也称为ADL或Koenig查找,是查找函数调用表达式中未限定函数名称的规则,包括对重载运算符的隐含函数调用。这些函数名称在其参数的命名空间中被查找,除了通常的未限定名称查找考虑的作用域和命名空间之外。
参数依赖查找使得能够使用在不同命名空间中定义的运算符。
在你的例子中,来自命名空间nsa2足以让编译器在寻找print时也考虑ns
你的例子有趣的一部分在于int_type也来自ns,尽管它只是一个typedef,并且int没有在ns中声明。请注意,typedef不会引入新类型(而是一个别名)。因此,a2实际上是一个intPS:这不仅适用于Visual Studio。符合标准的任何编译器都应该接受发布的代码。

但为什么不是 a1 呢? - acraig5075
@acraig5075 很好的问题。似乎 ADL 不会触发 typedef。a1 只是一个 int - 463035818_is_not_a_number
是的,ADL基于参数的类型。ns::int_type a1;int a1;完全等效,类型int没有“关联的命名空间”。 - aschepler
@StefanKarlsson 关于“我不能说我对这个设计选择感到满意”的问题 - 我无法想象没有 ADL,操作符重载会是多么不切实际的,尽管在其他地方,ADL 主要是混淆的根源。 - 463035818_is_not_a_number
@StefanKarlsson 编译器的细节比较少见,我更喜欢专注于C++,只有在涉及编译器特定内容时才会提及。无论如何,如果您认为答案中缺少相关信息,请随意编辑。 - 463035818_is_not_a_number
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接