柯尼希的查找适用于这里吗?

Does Koenig's lookup apply here?

本文关键字:这里 适用于 查找      更新时间:2023-10-16

以下代码段是正确的c++代码吗?

#include <sstream>
class Foo;
std::ostream& operator<<(std::ostream& str, Foo x);  // (A)
namespace test {
  class Message {
  public:
    std::ostringstream str;
  };
  template<typename T>
  Message& operator<<(Message& m, T& t)
  {
    using ::operator<<;
    m.str << t;
    return m;
  }
}
namespace detail {
  class Class {
  public:
    int i;
    Class() : i(5) {}
  };
}
std::ostream& operator<<(std::ostream& str, detail::Class& myClass) { // (B)
  return str << myClass.i;
}
int main() {
  test::Message m;
  detail::Class c;
  m << c;
}

根据http://goo.gl/NkPNau, GCC编译得很好,而Clang没有找到operator<< (B)。


如果你想知道:这是从一个代码,使用GTest与自定义operator<<std::set打印漂亮的断言消息。我们无法找出一种方法,使它与clang工作,而不是把operator<< (B)在std命名空间(是的,我知道…)。

Clang是正确的。我们把g++的行为称为语言扩展。

参数依赖查找(又名Koenig查找)确实适用,因为m.str << t是使用匹配m.str.operator<<(t)operator<<(m.str, t)的最佳重载来解释的,第二种情况是未限定id作为函数名。但是:

14.6.4.2:

对于依赖于模板形参的函数调用,使用通常的查找规则(3.4.1,3.4.2,3.4.3)查找候选函数,除了:

  • 对于使用非限定名查找(3.4.1)或限定名查找(3.4.3)的查找部分,只查找来自模板定义上下文的函数声明。

  • 对于使用关联命名空间查找的部分(3.4.2),只查找在模板定义上下文中或模板实例化上下文中找到的函数声明。

如果函数名是非限定id,并且如果在关联的命名空间内查找考虑所有翻译单元中在这些命名空间中引入的带有外部链接的所有函数声明,而不仅仅考虑在模板定义和模板实例化上下文中找到的那些声明,则调用将是错误的,或者将找到更好的匹配,则程序具有未定义行为。

在模板定义上下文中,(B)不可见。(B)在模板实例化上下文中是可见的,但是全局命名空间不是std::ostringstreamdetail::Class的关联命名空间。