简体   繁体   English

带名称空间的编译器的有趣行为

[英]Interesting behavior of compiler with namespaces

Assume the following code: 假设以下代码:

#include <iostream>
using namespace std;

namespace X
{
  class A{};

  void f(A a){}

  void g(int a){}
}

int main()
{
  X::A a;
  f(a);
  g(5);
}

When I compile the code, the following compile error occurs: 编译代码时,会发生以下编译错误:

main.cpp: In function 'int main()': main.cpp:在函数'int main()'中:
main.cpp: error: 'g' was not declared in this scope main.cpp:错误:在此范围内未声明'g'

So the function f is compiled perfectly, but g isn't. 因此函数f被完美地编译,但g不是。 How? 怎么样? Both of them belong to the same namespace. 它们都属于同一名称空间。 Does the compiler deduce that function f belongs to the X namespace from the argument of type X::A ? 编译器是否从类型X::A的参数推断出函数f属于X命名空间? How does compiler behave in such cases? 在这种情况下编译器如何表现?

X::A a;
f(a);

works because of Argument-Dependent Lookup (Also known as Koenig Lookup). 因为Argument-Dependent Lookup (也称为Koenig Lookup)而起作用。 a is an object of class A inside namespace X , when compiler searches a match-able function f , it will look into namespace X in this case. a是命名空间X的类A的对象,当编译器搜索可匹配的函数f ,它将在这种情况下查看命名空间X See Argument Dependent Lookup for more information. 有关更多信息,请参阅参数依赖查找

This works for the function call expression: 这适用于函数调用表达式:

f(a);

because the namespace that X::A belongs to is included in the lookup for the function f due to argument dependent lookup( ADL ) , cppreference explains ADL as follows: 因为X::A所属的命名空间由于参数依赖查找( ADL而包含在函数f 查找中 ,所以cppreference解释ADL如下:

Argument-dependent lookup, also known as ADL, or Koenig lookup, is the set of rules for looking up the unqualified function names in function-call expressions, including implicit function calls to overloaded operators. 依赖于参数的查找(也称为ADL或Koenig查找)是用于在函数调用表达式中查找非限定函数名称的规则集,包括对重载运算符的隐式函数调用。 These function names are looked up in the namespaces of their arguments in addition to the scopes and namespaces considered by the usual unqualified name lookup. 除了通常的非限定名称查找所考虑的范围和名称空间之外,还会在其参数的名称空间中查找这些函数名称。

Argument-dependent lookup makes it possible to use operators defined in a different namespace 依赖于参数的查找使得可以使用在不同命名空间中定义的运算符

This is covered in the draft C++ standard section 3.4.2 Argument-dependent name lookup : 这在C ++标准草案部分3.4.2 参数依赖名称查找中有所介绍:

When the postfix-expression in a function call (5.2.2) is an unqualified-id, other namespaces not considered during the usual unqualified lookup (3.4.1) may be searched, and in those namespaces, namespace-scope friend function or function template declarations (11.3) not otherwise visible may be found 函数调用(5.2.2)中的postfix-expression 是非限定id时,可以搜索在通常的非限定查找(3.4.1)期间未考虑的其他命名空间,并且在这些命名空间中,命名空间范围的朋友函数或函数可以找到不可见的模板声明(11.3)

and goes on to say: 接着说:

For each argument type T in the function call, there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered. 对于函数调用中的每个参数类型T,存在一组零个或多个关联的命名空间以及要考虑的一组零个或多个关联的类。 The sets of namespaces and classes is determined entirely by the types of the function arguments (and the namespace of any template template argument). 命名空间和类的集合完全由函数参数的类型(以及任何模板模板参数的命名空间)决定。

and includes the following bullet: 并包括以下项目:

If T is a class type (including unions), its associated classes are: the class itself; 如果T是类类型(包括联合),则其关联的类是:类本身; the class of which it is a member, if any; 它所属的成员,如果有的话; and its direct and indirect base classes. 及其直接和间接基类。 Its associated namespaces are the namespaces of which its associated classes are members .[...] 其关联的名称空间是其关联类是成员的名称空间 。[...]

and further down provides a similar example to your problem: 进一步向下提供了一个与您的问题类似的示例:

namespace NS {
  class T { };
  void f(T);
  void g(T, int);
}

NS::T parm;
void g(NS::T, float);

int main() {
  f(parm); // OK: calls NS::f
  extern void g(NS::T, float);
  g(parm, 1); // OK: calls g(NS::T, float)
}

The function call expression: 函数调用表达式:

g(5);

does not work because ADL does not add any namespaces for arguments that are fundamental types. 不起作用,因为ADL不为基本类型的参数添加任何名称空间。

Herb Sutter covers ADL in Gotw #30 and in What's In a Class? Herb Sutter在Gotw#30什么是 同类课程中涵盖了ADL - The Interface Principle . - 接口原理

When the code f(a) , the compiler finds the function void f(A a){} in the namespace X because of the ADL (argument dependent lookup, also known as Koenig lookup). 当代码f(a) ,编译器在namespace X找到函数void f(A a){} ,因为ADL (参数依赖查找,也称为Koenig查找)。

A is declared in the namespace X , hence when the compiler needs to look up the definition of f , it includes possibilities from that namespace because the object a of type A is in that namespace (as declared X::A a; ). A在名称空间X声明,因此当编译器需要查找f的定义时,它包含来自该名称空间的可能性,因为类型A的对象a在该名称空间中(如声明的X::A a; )。

On the other hand, int is not declared in the namespace X , so the namespace X is not included in the lookup. 另一方面, int未在namespace X声明,因此namespace X不包含在查找中。 Since no corresponding function for f is found, it fails to compile. 由于没有找到f相应函数,因此无法编译。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM