使用带有boost :: optional的相等运算符 [英] Using equality operators with boost::optional

查看:202
本文介绍了使用带有boost :: optional的相等运算符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图为另一个命名空间中定义的类型T定义一个相等运算符,然后在 optional< T> 上使用相等运算符。在clang(Apple LLVM 9.1.0)上,此代码:

I'm trying to define an equality operator for a type T defined in another namespace, and then use the equality operator on optional<T>. On clang (Apple LLVM 9.1.0), this code:

    namespace nsp {
        struct Foo {
        };
    }
    bool operator==(const nsp::Foo& a, const nsp::Foo& b);

    void foo() {
        optional<nsp::Foo> a = none;
        optional<nsp::Foo> b = none;
        if (a == b)
            ;
    }

导致错误:

/usr/local/include/boost/optional/detail/optional_relops.hpp:29:34: error: invalid operands to binary expression ('const nsp::Foo' and 'const nsp::Foo')
{ return bool(x) && bool(y) ? *x == *y : bool(x) == bool(y); }
                      ~~ ^  ~~
MWE.cpp:40:19: note: in instantiation of function template specialization 'boost::operator==<what3words::engine::nsp::Foo>' requested here
            if (a == b)
                  ^
/usr/local/include/boost/optional/detail/optional_relops.hpp:28:6: note: candidate template ignored: could not match 'optional<type-parameter-0-0>' against 'const nsp::Foo'
bool operator == ( optional<T> const& x, optional<T> const& y )

发生了什么事?我的猜测是,这与Koenig查找规则有关...

What's happening? My guess is that it's something to do with the Koenig lookup rules...

推荐答案

立即修复



执行以下操作:

Immediate fix

Do this:

namespace nsp {
  bool operator==(const Foo& a, const Foo& b);
}

可以解决您的问题。

如果您可以控制 Foo ,则可以执行以下操作:

If you have control over Foo, you can instead do:

namespace nsp {
  struct Foo {
    friend bool operator==(const Foo& a, const Foo& b) {
      return true;
    }
  };
}

如果 Foo 是模板类。

这是怎么回事可选 std 中(或 boost 或其他)中,在该命名空间中,它尝试执行 nsp :: Foo == nsp :: Foo 调用。

What is going on here is that optional is in std (or boost or whatever) and in that namespace it tries to do a nsp::Foo == nsp::Foo call.

== 不适用于 :: std 命名空间,因此不会在 :: ;一旦找到 any == ,即使参数完全无关,它也会停止查找。它还在与参数关联的命名空间中查找 == ,在本例中为 :: nsp

There is a == that doesn't apply in the ::std namespace, so it won't look in ::; once it finds any == it stops looking, even if the arguments are completely unrelated. It also looks for == in the namespaces associated with the arguments -- in this case ::nsp. But it never looks in :: here either.

将操作符添加到类型时,请始终在以下位置定义操作符:

When adding operators to a type, always define the operator in the namespace of the type.

可以重新打开名称空间。因此,如果您无法控制头文件,则可以使用其中的 == 创建一个新的头文件。 == 必须在每个 optional< nsp :: Foo> :: operator == 所在的位置都可见

Namespaces can be reopened. So if you don't have control over the header file, you can create a new header file with the == in it. This == has to be visible at every point where optional<nsp::Foo>::operator== is invoked or your program is ill formed due to ODR violations (and, in this case, also generates a compiler error, which is useful to avoid heizenbugs).

当您调用运算符(或函数)时,查找遵循几个简单的步骤。

When you invoke an operator (or a function), lookup follows a few simple steps.

首先在本地(在本地名称空间中)环顾四周。如果在该处找到任何内容,该搜索将停止。 (这包括使用ns :: identifier; 注入名称空间的名称,但通常不<使用名称空间foo; )。即使该功能或运算符不适用于所讨论的类型,也会发生停止;命名空间中任何类型的任何 == 都会停止搜索。

First it looks around locally (in the local namespace). If it finds anything there, this search stops. (This includes using ns::identifier; names injected into the namespace, but usually not using namespace foo;). This "stop" occurs even if the function or operator won't work for the types in question; any == for any types whatsoever in a namespace stops this search.

如果找不到匹配项,它开始寻找封闭的名称空间,直到找到函数/运算符或到达根名称空间为止。如果存在 using命名空间foo; 声明,则将这些命名空间中的函数/运算符视为在 using的公共父命名空间中名称空间位置和要导入的名称空间。 (因此,使用命名空间std; namespace foo 中使其看起来像 std 位于 :: 中,而不位于 foo )中。

If that fails to find a match, it starts looking in enclosing namespaces until it finds the function/operator, or reaches the root namespace. If there are using namespace foo; declarations, the functions/operators in those namespaces are considered to be in the "common parent" namespace of both the using namespace location and the namespace being imported. (So using namespace std; in namespace foo makes it seem like std is in ::, not in foo).

结果生成了用于重载解决方案的候选集合。

The result generates a collection of candidates for overload resolution.

接下来,完成ADL(依赖于参数的查找)。检查所有函数/运算符参数的关联名称空间。此外,还(递归地)检查了模板所有类型参数的关联命名空间。

Next, ADL (argument dependent lookup) is done. The associated namespaces of all function/operator arguments are examined. In addition, the associated namespaces of all the type arguments of the templates are also examined (recursively).

与名称匹配的操作符/函数被收集。对于ADL,不检查父名称空间。

Operators/functions that match the name are collected. For ADL, parent namespaces are not examined.

这两个运算符/函数集合是重载解析的候选对象。

These two collections of operators/functions are your candidates for overload resolution.

在您的情况下,调用 == 的命名空间为 boost boost 有很多 == 运算符(即使它们不适用),因此所有<$ c boost 中的$ c> == 是候选对象。

In your case, the namespace where == is called is boost. boost has plenty of == operators (even if they don't apply), so all of the == in boost are candidates.

接下来,我们检查参数的名称空间-在这种情况下为 nsp :: Foo 。我们查看 nsp ,看不到 ==

Next, we examine the namespace of the arguments -- nsp::Foo in this case. We look in nsp and see no ==.

然后,我们对它们进行重载解析。没有候选者有效,并且会出现编译器错误。

Then we run overload resolution on those. No candidates work, and you get a compiler error.

现在,当您移动用户定义的 == 时放入命名空间nsp 中,然后将其添加到在ADL步骤中找到的 == 的集合中。

Now, when you move your user-defined == into namespace nsp, it is then added to the set of == found in the ADL step. And as it matches, it is called.

超载分辨率(对候选人的处理方式)是其自身的复杂主题。简短的形式是它尝试查找涉及最少转换量的重载。并且如果两个情况彼此完全匹配,则它首选非模板而不是模板,并且非变量而不是变量。

Overload resolution (what it does with the candidates) is its own complex subject. The short form is that it tries to find the overload that involves the least amount of conversion; and if two cases match exactly as well as each other, it prefers non-template over template and non-variardic over variardic.

至少有很多细节转换数量和完全可能会误导程序员。最常见的是将 Foo 左值转换为 Foo const& 只是很小的转换,可以转换为 template< class T> T& T& 不进行转换。

There is a lot of detail in "least amount of conversion" and "exactly" that can mislead programmers. The most common is is that converting a Foo lvalue to Foo const& is a small amount of conversion, convering it to template<class T> T&& or T& is no conversion.

这篇关于使用带有boost :: optional的相等运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆