以下代码段正确的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;
}
Run Code Online (Sandbox Code Playgroud)
根据http://goo.gl/NkPNau,GCC汇编了这个罚款,而Clang没有找到operator<<(B).
如果你想知道:这是从使用GTEST使用自定义代码operator<<对std::set打印好的断言消息.除了把operator<<(B)放在std命名空间(是的,我知道......)之外,我们无法找到一种方法来使它与clang一起工作.
Clang在这里是正确的。我们将 g++ 的行为称为语言扩展。
依赖于参数的查找(又名 Koenig 查找)确实适用,因为使用与或m.str << t匹配的最佳重载进行解释,而第二种情况是使用unqualified-id作为函数名称。但:m.str.operator<<(t)operator<<(m.str, t)
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::ostringstream空间detail::Class。