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

Joh*_*mew 14 c++ argument-dependent-lookup

在编写测试套件时,我需要提供一个operator<<(std::ostream&...Boost单元测试的实现来使用.

这有效:

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 << ")");
    }
}}
Run Code Online (Sandbox Code Playgroud)

这没有:

std::ostream& operator<<(std::ostream& ss, const theseus::core::PixelRGB& p) {
    return (ss << "PixelRGB(" << (int)p.r << "," << (int)p.g << "," << (int)p.b << ")");
}
Run Code Online (Sandbox Code Playgroud)

显然,当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()
Run Code Online (Sandbox Code Playgroud)

作为参考,我正在使用g ++ 4.4(虽然目前我假设这种行为符合标准).

dan*_*ncl 11

在参数依赖查找(koenig查找的正确名称)中,编译器向重载函数集添加在每个参数的名称空间中声明的函数.

在您的情况下,第一个operator<<在命名空间thesus::core,中声明,该命名空间是您调用操作符的参数的类型.因此,这operator<<被考虑用于ADL,因为它在关联的命名空间中声明

在第二种情况下,operator<<似乎在全局命名空间中声明了它不是关联的命名空间,因为参数1是来自命名空间的类型,std而参数2是来自命名空间的类型theseus::core.

实际上,可能你的第二个operator<<没有在全局命名空间中声明,因为通过查看父范围可以找到它.也许你有更像这样的东西?如果您可以发布更多代码,我们可以给出更好的答案.


好吧我记得,当ADL在当前作用域中找到名称时,它不会在父作用域中查找.因此,boost宏BOOST_TEST_MESSAGE扩展为包括a,operator<<并且范围树中的一些在operator<<表达式和全局范围之间是不可行的.我更新了代码来说明这一点(希望如此).

#include <iostream>

namespace NS1
{
  class A
  {};

  // this is found by expr in NS2 because of ADL
  std::ostream & operator<<(std::ostream &, NS1::A &);
}


// this is not seen because lookup for the expression in NS2::foo stops when it finds the operator<< in NS2
std::ostream & operator<<(std::ostream &, NS1::A &);

namespace NS2
{
    class B
    {};

    // if you comment this out lookup will look in the parent scope
    std::ostream & operator<<(std::ostream &, B &);

    void foo(NS1::A &a)
    {
        std::cout << a;
    }  
}
Run Code Online (Sandbox Code Playgroud)

  • 确切地说,全局命名空间没有关联,因为增强单元测试的东西不是全局的.这是一种防止非预期的函数注入模板代码的功能. (2认同)