STL中带有运算符==的名称空间解析

问题描述 投票:3回答:4

在名称空间中考虑一个简单的类型,并带有operator==

namespace ANamespace {
    struct Foo { int i; float f; };
}

#ifdef INSIDE

namespace ANamespace {
    bool operator==(const Foo& l, const Foo& r)
    {
        return l.i == r.i && l.f == r.f;
    }
}

#else

bool operator==(const ANamespace::Foo& l, const ANamespace::Foo& r)
{
    return l.i == r.i && l.f == r.f;
}

#endif

bool compareElements(const std::vector<ANamespace::Foo>& l, const std::vector<ANamespace::Foo>& r)
{
    return l == r;
}

如果在operator==内部定义了ANamespace(通过定义INSIDE),则编译示例。但是,如果在全局名称空间中定义了operator==(在#else情况下),则函数compareElements()不会编译-在GCC和Clang中,以及libstdc ++和libc ++都不会编译。全部都按照以下方式发出模板错误:

In file included from /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../include/c++/9.2.0/vector:60:
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/stl_algobase.h:820:22: error: invalid operands to binary expression ('const ANamespace::Foo' and 'const ANamespace::Foo')
            if (!(*__first1 == *__first2))
                  ~~~~~~~~~ ^  ~~~~~~~~~
...

但是,直接比较一个函数中的两个Foo,例如

bool compareDirectly(const ANamespace::Foo& l, const ANamespace::Foo& r)
{
    return l == r;
}

无论在何处定义operator==,似乎都能正常工作。

标准中是否有关于STL期望在何处定义operator==的规则?

c++ stl namespaces operator-overloading
4个回答
2
投票

!(*__first1 == *__first2)发生在函数模板std::operator==中,因此它被视为相关的不合格函数调用表达式,因此在重载解析期间,只有在std::operator==定义上下文中找到的函数和通过ADL找到的函数才是候选函数。

显然,在标准比较运算符的定义上下文中没有声明operator==(const Foo&, const Foo&)。在基于参数的查找(ADL)中,将检查每个参数的名称空间以搜索该调用的可行函数,因此这就是在operator==内部定义ANamespace起作用的原因。


0
投票

简而言之,在声明类的同一个名称空间中声明operator==可以确保依赖于参数的查找将找到它,因此您应该这样做。该标准并不强制您遵守此约定,但实际上,这是获得保证的唯一方法。这也适用于标准库可能在您的类型上调用的其他运算符。

如果您选择在全局名称空间中声明operator==,但您的类型在全局名称空间中声明了[[not,则标准库算法仍有可能通过非限定词来查找您的operator==名称查询。但是,不能保证这行得通,因为不合格的名称查找将在找到operator==的最内层的命名空间中stop。换句话说,采用以下形式的算法:namespace std { template< class InputIt1, class InputIt2 > constexpr bool equal( InputIt1 first1, InputIt1 last1, InputIt2 first2 ) { // ... } }

operator==的非限定名称查找将找到在operator==命名空间中声明的所有std(当然,不适用于您的用户定义类型),然后,如果在std中找到了任何内容],即使它可能不是可行的重载,也不会在全局名称空间中查看。

0
投票
您需要阅读“ ADL”或“依赖于参数的查询”。

0
投票
您需要阅读“ ADL”或“依赖于参数的查询”。
© www.soinside.com 2019 - 2024. All rights reserved.