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

c++ Output stream not working with templates and namespaces

本文关键字:命名空间 适用于 输出流 不适用 c++      更新时间:2023-10-16

我有以下代码:

#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上编译,并失败,并显示以下错误消息:

错误C2679:二进制'<lt;':找不到占用右手的运算符类型为"baz::Bar"的操作数(或者没有可接受的转换)

但是,如果我移除这两个名称空间中的任何一个(保留所有内容),或者移除Point类的模板化<<函数,一切都会正常工作。

这是MSVC中的一个错误吗?如何在不删除名称空间或函数的情况下进行编译

这是代码中的一个错误。功能的过载集分多个阶段构建:

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

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

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