C ++运算符查找规则/ Koenig查找

时间:2011-01-05 12:16:23

标签: c++ argument-dependent-lookup

在编写测试套件时,我需要为使用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(虽然目前我假设这种行为符合标准)。

2 个答案:

答案 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原则。您必须在正确的命名空间中定义运算符重载。