在编写测试套件时,我需要为使用Boost单元测试提供operator<<(std::ostream&...
的实现。
这有效:
namespace theseus { namespace core {
std::ostream& operator<<(std::ostream& ss, const PixelRGB& p) {
return (ss << "PixelRGB(" << (int)p.r << "," << (int)p.g << "," << (int)p.b << ")");
}
}}
这不是:
std::ostream& operator<<(std::ostream& ss, const theseus::core::PixelRGB& p) {
return (ss << "PixelRGB(" << (int)p.r << "," << (int)p.g << "," << (int)p.b << ")");
}
显然,当g ++尝试解决运算符的使用时,第二个未包括在候选匹配中。为什么(什么规则会导致这种情况)?
调用operator<<
的代码深入Boost单元测试框架,但这里是测试代码:
BOOST_AUTO_TEST_SUITE(core_image)
BOOST_AUTO_TEST_CASE(test_output) {
using namespace theseus::core;
BOOST_TEST_MESSAGE(PixelRGB(5,5,5)); // only compiles with operator<< definition inside theseus::core
std::cout << PixelRGB(5,5,5) << "\n"; // works with either definition
BOOST_CHECK(true); // prevent no-assertion error
}
BOOST_AUTO_TEST_SUITE_END()
作为参考,我正在使用g ++ 4.4(虽然目前我假设这种行为符合标准)。
答案 0 :(得分:11)
在参数依赖查找(koenig查找的正确名称)中,编译器向重载函数集添加在每个参数的名称空间中声明的函数。
在您的情况下,第一个operator<<
在名称空间thesus::core,
中声明,这是您调用运算符的参数的类型。因此,operator<<
被认为是ADL,因为它是在关联的命名空间中声明的
在第二种情况下,operator<<
似乎在全局命名空间中声明,该命名空间不是关联的命名空间,因为参数1是来自命名空间std
的类型,而参数2是来自命名空间{的类型{ {1}}。
实际上,可能你的第二个theseus::core
没有在全局命名空间中声明,因为通过查看父范围可以找到它。也许你有更像这样的东西?如果您可以发布更多代码,我们可以给出更好的答案。
好的我记得,当ADL在当前作用域中找到名称时,它不会在父作用域中查找。因此,boost宏operator<<
扩展为包含BOOST_TEST_MESSAGE
,并且范围树中的某些内容在表达式和全局范围之间存在不可行operator<<
。我更新了代码来说明这一点(希望如此)。
operator<<
答案 1 :(得分:1)
运算符重载就像一个函数但不同,其中一个区别就是命名空间查找。
与函数类似,运算符重载属于命名空间,但是确定函数范围的方式是不切实际的。想象一下,如果您的代码必须调用
std::cout thesus::core::<< p; // ouch and obviously incorrect syntax
因此,<<
运算符必须位于其中一个参数的命名空间中,std
(对于cout
)或p
的命名空间,在此案例thesus::core
。
这是Koenig Lookup原则。您必须在正确的命名空间中定义运算符重载。