以下代码段是否正确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
的代码来打印好的断言消息。除了将operator<<
(B)放在std命名空间(是的,我知道......)之外,我们无法找到使其与clang一起使用的方法。
答案 0 :(得分:3)
Clang在这里是正确的。让我们将g ++的行为称为语言扩展。
依赖于参数的查找(又名Koenig查找)确实适用,因为m.str << t
使用匹配m.str.operator<<(t)
或operator<<(m.str, t)
的最佳重载进行解释,第二种情况是 unqualified-id 作为函数名称。但是:
14.6.4.2:
对于依赖于模板参数的函数调用,使用通常的查找规则(3.4.1,3.4.2,3.4.3)找到候选函数,除了:
对于使用非限定名称查找(3.4.1)或限定名称查找(3.4.3)的查找部分,只能找到模板定义上下文中的函数声明。
对于使用关联命名空间(3.4.2)的查找部分,只能找到模板定义上下文或模板实例化上下文中找到的函数声明。
如果函数名称是 unqualified-id ,并且调用结果不正确或者找到更好的匹配,则相关命名空间中的查找会考虑所有带有外部链接的函数声明所有翻译单元中的名称空间,不仅仅考虑模板定义和模板实例化上下文中的那些声明,那么程序就有未定义的行为。
在模板定义上下文中,(B)不可见。 (B)在模板实例化上下文中可见,但全局命名空间不是std::ostringstream
或detail::Class
的关联命名空间。