c ++输出流不适用于模板和名称空间

c++ Output stream not working with templates and namespaces

我有以下代码:

#include <fstream>

// Removing this namespace (keeping the content) makes it work
namespace baz {

class Bar {
};

}

std::ostream & operator<<(std::ostream & stream, baz::Bar & value) {
  return stream;
}

// Removing this namespace (keeping the content) makes it work
namespace goo {

template <class Type>
struct Point {
};

// Removing this function makes it work
template <class Type>
std::ostream& operator<< (std::ostream& stream, const Point<Type> &point);

void foo() {
  baz::Bar test;
  std::ofstream stream;
  stream << test;
}

}

它无法在 MSVC 上编译并失败并显示以下错误消息:

error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'baz::Bar' (or there is no acceptable conversion)

但是,如果我删除两个命名空间中的任何一个(保留所有内容)或删除 Point class 的模板化 << 函数,一切正常。

这是 MSVC 中的错误吗?如何在不删除命名空间或函数的情况下编译它?

这是您的代码中的错误。函数的重载集是分多个阶段构建的:

  1. 从当前范围向外找到一个匹配的函数名。当在命名空间中找到名称时,将此命名空间中定义的所有重载添加到重载集中并停止此过程。
  2. 将参数相关查找 (ADL) 找到的所有重载添加到重载集中。
  3. 确定重载集是否包含唯一匹配和最佳重载。如果是这样,使用它,否则失败。

您的问题是您的 operator<<(std::ostream&, baz::Bar&) 是在全局命名空间中定义的,而不是在定义 Bar 的命名空间中(在本例中为 baz)。当使用名称取决于模板参数的模板中的运算符时,无论如何都需要将重载放入命名空间 baz 中:在这种情况下,第一阶段被省略,并且仅检测到通过参数相关查找找到的名称。

顺便说一句,在固定输出运算符的位置时,您可能需要考虑将参数作为 baz::Bar const& 传递,因为输出运算符通常不会修改格式化实体。