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

发布于 2024-10-10 14:29:48 字数 1257 浏览 0 评论 0原文

在编写测试套件时,我需要提供 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 << ")");
    }
}}

这没有:

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(尽管目前我假设此行为符合标准)。

While writing a test suite, I needed to provide an implementation of operator<<(std::ostream&... for Boost unit test to use.

This worked:

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 << ")");
    }
}}

This didn't:

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

Apparently, the second wasn't included in the candidate matches when g++ tried to resolve the use of the operator. Why (what rule causes this)?

The code calling operator<< is deep within the Boost unit test framework, but here's the test code:

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()

For reference, I'm using g++ 4.4 (though for the moment I'm assuming this behaviour is standards-conformant).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浅听莫相离 2024-10-17 14:29:48

在参数相关查找(koenig 查找的正确名称)中,编译器将在每个参数的命名空间中声明的函数添加到重载函数集中。

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

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

实际上,您的第二个运算符<<<可能没有在全局名称空间中声明,因为可以通过在父作用域中查找来找到它。也许您有更多类似的东西?如果您可以发布更多代码,我们可以给出更好的答案。


好吧,我记得,当 ADL 在当前作用域中找到名称时,它不会在父作用域中查找。因此,boost 宏 BOOST_TEST_MESSAGE 扩展为包含一个 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;
    }  
}

In argument dependent lookup (the correct name for koenig lookup) the compiler adds to the overloaded function set the functions which are declared in the namespaces of each parameter.

In your case, the first operator<< is declared in the namespace thesus::core, which is the type of the argument you call the operator with. Therefore this operator<< is considered for ADL because it's declared in an associated namespace

In the second case, the operator<< seems to be declared in the global namespace which is not an associated namespace as parameter one is of type from namespace std and param 2 is of type from namespace theseus::core.

Actually, probably your 2nd operator<< isn't declared in global namespace as that would be found through looking in parent scopes.. maybe you've got something more like this? If you can post more code we can give a better answer.


Ok I remembered, ADL doesn't lookup in parent scopes when it finds a name in the current scope. So the boost macro BOOST_TEST_MESSAGE expands to include an operator<< and there is some in the scope tree a non-viable operator<< between the expression and global scope. I updated code to illustrate this (hopefully).

#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;
    }  
}
冷︶言冷语的世界 2024-10-17 14:29:48

运算符重载类似于函数,但有所不同,其中区别之一是命名空间查找。

与函数一样,运算符重载属于命名空间,但确定函数作用域的方式是不切实际的。想象一下,如果您的代码必须调用

std::cout thesus::core::<< p; // ouch and obviously incorrect syntax

因此 << 运算符必须位于其中一个参数的命名空间中,即 std (对于 cout) 或 p 的命名空间,在本例中为 thesus::core

这就是 Koenig 查找原理。您必须在正确的命名空间中定义运算符重载。

Operator overloading is like a function but differs, and one of the differences is namespace lookup.

Like functions, operator overloads belong in a namespace, but scoping the way you scope a function would be impractical. Imagine if your code had to call

std::cout thesus::core::<< p; // ouch and obviously incorrect syntax

Therefore the << operator must be in the namespace of one of the parameters, either std (for the cout) or the namespace of the p, in this case thesus::core.

This is the Koenig Lookup principle. You must define the operator overload in the correct namespace.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文