c++ - 命名空间和运算符解析

标签 c++ namespaces operator-keyword

我正在使用一个在全局命名空间中定义输出流运算符 (operator<<) 的库。在我自己的命名空间中,我总是在全局命名空间中声明这样的运算符,并且从来没有遇到过问题。但是现在由于各种原因,我需要在自己的命名空间中声明这些运算符,突然间,编译器似乎再也找不到库中声明的运算符了。

这里有一个简单的例子来说明我的问题:

#include <iostream>

namespace A
{
   struct MyClass {};
}

std::ostream & operator<<( std::ostream & os, const A::MyClass & )
   { os << "namespace A"; return os; }

namespace B
{
   struct MyClass {};

   std::ostream & operator<<( std::ostream & os, const B::MyClass & )
      { os << "namespace B"; return os; }
}

namespace B
{
   void Test()
   {
      std::cout << A::MyClass() << std::endl;
      std::cout << B::MyClass() << std::endl;
   }
}

int main()
{
   B::Test();
   return 1;
}

我收到以下错误:

error: no match for ‘operator<<’ in ‘std::cout << A::MyClass()’

请注意,如果两个运算符都在命名空间中,或者如果它们都在全局命名空间中,则代码可以正确编译和执行。

我真的很想了解发生了什么,以及使用命名空间定义此类运算符的“良好做法”。

谢谢!

最佳答案

自从 Test位于命名空间 B编译器在该命名空间中看到该运算符,并指出它没有匹配的签名。它还尝试在 namespace A 中找到包含该类但也找不到该类的运算符。因为命名空间B 中已经有这样的运算符(签名错误)它不会去尝试在全局范围内找到一个。

它不搜索全局的原因大致如下。我先引用标准,然后再解释一下。

从 3.4/1 开始:

...Name lookup may associate more than one declaration with a name if it finds the name to be a function name; the declarations are said to form a set of overloaded functions (13.1). Overload resolution (13.3) takes place after name lookup has succeeded.

当我读到这篇文章时,当编译器试图找到一个函数(你的操作符在这个上下文中)时,它首先会尝试进行名称查找以首先找到该函数。然后接下来它会尝试从重载集中选择正确的函数。

现在从 3.4.1/6 开始:

A name used in the definition of a function(26) that is a member of namespace N (where, only for the purpose of exposition, N could represent the global scope) shall be declared before its use in the block in which it is used or in one of its enclosing blocks (6.3) or, shall be declared before its use in namespace N or, if N is a nested namespace, shall be declared before its use in one of N’s enclosing namespaces.

让我们分解一下。您正在使用 operator<<在命名空间级别函数中,因此本节适用。它将尝试使用上述优先级来查找该运算符。您的运算符未在当前 block 或封闭 block 中声明(这是指嵌套在您的函数中的 {})。然而,下一部分匹配“...shall be declared before its use in namespace N...”。 实际上是一个operator<<在当前命名空间( B )中,因此它将该运算符添加到其匹配列表中。 B 中没有更多匹配项,并且由于相同命名空间范围被认为是最佳匹配接近度,因此它不会查看任何其他范围。

将操作符放入命名空间 A 时它起作用的原因是因为正在打印的项目是 A 的成员,实际上考虑了该命名空间,因为它包含在表达式的命名空间中。自命名空间 A 认为它在该命名空间中找到了适当的匹配项并正确编译。

现在它有一个可能的运算符列表,它会尝试对它们进行重载决策。不幸的是,在命名空间 B 中找到的那个是它唯一考虑的那个,它与所需的参数不匹配。

一般来说,插入操作符应该与它所操作的类在同一个命名空间中。

关于c++ - 命名空间和运算符解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5195512/

相关文章:

matlab - 如何在 Matlab 中正确重载 size() 方法/运算符

c++ - MFC CArray 上的 std::reverse

c++ - 所以文件: function called from another so file than intended

c++ - 有没有一种方法可以在不使用 new 的情况下从函数返回抽象(出于性能原因)

php - 如何调用另一个命名空间中的方法

c++ - 为什么在模板中调用基类的运算符?

c++ - 错误 C2064 : term does not evaluate to a function taking 0 arguments

c - C中 block 作用域和函数作用域的区别

c++ - 有没有更好的方法在 header 中用 C++ 表达嵌套命名空间

c++ - 重载 "+"运算符,结果错误?