将相等运算符与 boost::Optional 一起使用

2024-01-06

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

    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 查找规则有关......


立即修复

Do this:

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

解决你的问题。

如果你有控制权Foo,你可以这样做:

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

这是最佳的,如果Foo是一个模板类。

您的解决方案出了什么问题

这里发生的事情是这样的optional is in std (or boost或其他)并在该名称空间中尝试执行nsp::Foo == nsp::Foo call.

有一个==这不适用于::std命名空间,所以它不会查找::;一旦发现any ==即使参数完全不相关,它也会停止查找。它还寻找==在与参数关联的命名空间中——在本例中::nsp。但它从来不看::这里也可以。

将运算符添加到类型时,请始终在该类型的命名空间中定义该运算符。

命名空间可以重新打开。因此,如果您无法控制头文件,您可以使用以下命令创建一个新的头文件==在里面。这==必须在每个地方都可见optional<nsp::Foo>::operator==被调用或者您的程序由于 ODR 违规而格式不正确(在这种情况下,还会生成编译器错误,这对于避免 heizenbug 很有用)。

长版

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

首先,它在本地(在本地命名空间中)查找。如果在那里发现任何东西,搜索就会停止。 (这包括using ns::identifier;名称注入到命名空间中,但通常不是using namespace foo;)。即使函数或运算符不适用于相关类型,也会发生这种“停止”;任何==对于命名空间中的任何类型,都会停止此搜索。

如果找不到匹配项,它将开始查找封闭的命名空间,直到找到函数/运算符,或到达根命名空间。如果有using namespace foo;声明时,这些命名空间中的函数/运算符被视为位于两个命名空间的“公共父”命名空间中using namespace位置和正在导入的命名空间。 (所以using namespace std; in namespace foo让它看起来像std is in ::,不在foo).

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

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

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

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

在你的情况下,命名空间在哪里==被称为是boost. boost有很多==运算符(即使它们不适用),所以所有== in boost是候选人。

接下来,我们检查参数的名称空间——nsp::Foo在这种情况下。我们看看nsp并看到没有==.

然后我们对它们运行重载解析。没有候选人工作,你会得到一个编译器错误。

现在,当您移动用户定义的== into namespace nsp,然后将其添加到集合中==在 ADL 步骤中找到。当它匹配时,它就被称为。

超载解决方案(它对候选人的作用)本身就是一个复杂的主题。简而言之,它试图找到涉及最少转换量的重载;如果两种情况彼此完全匹配,则它会优先选择非模板而不是模板,并且优先选择非可变参数而不是可变参数。

“最少转换量”和“精确”中有很多细节可能会误导程序员。最常见的是转换Foo左值到Foo const&是一个小量的转换,将其转换为template<class T> T&& or T&是没有转换。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将相等运算符与 boost::Optional 一起使用 的相关文章

  • C++ 是否可以在 MacOS 上与 OpenMP 和 boost 兼容?

    我现在已经尝试了很多事情并得出了一些结论 也许 我监督了一些事情 但似乎我无法完成我想要的事情 问题是 是否有可能使用 OpenMP 和 boost 在 MacOS High Sierra 上编译 C 一些发现 如果我错了请纠正我 Open
  • 如何在C(Linux)中的while循环中准确地睡眠?

    在 C 代码 Linux 操作系统 中 我需要在 while 循环内准确地休眠 比如说 10000 微秒 1000 次 我尝试过usleep nanosleep select pselect和其他一些方法 但没有成功 一旦大约 50 次 它
  • 函数参数的默认参数是否被视为该参数的初始值设定项?

    假设我有这样的函数声明 static const int R 0 static const int I 0 void f const int r R void g int i I 根据 dcl fct default 1 如果在参数声明中指
  • 查看 NuGet 包依赖关系层次结构

    有没有一种方法 文本或图形 来查看 NuGet 包之间的依赖关系层次结构 如果您使用的是新的 csproj 您可以在此处获取所有依赖项 在项目构建后 项目目录 obj project assets json
  • C# 数据表更新多行

    我如何使用数据表进行多次更新 我找到了这个更新 1 行 http support microsoft com kb 307587 my code public void ExportCSV string SQLSyntax string L
  • Python 属性和 Swig

    我正在尝试使用 swig 为一些 C 代码创建 python 绑定 我似乎遇到了一个问题 试图从我拥有的一些访问器函数创建 python 属性 方法如下 class Player public void entity Entity enti
  • File.AppendText 尝试写入错误的位置

    我有一个 C 控制台应用程序 它作为 Windows 任务计划程序中的计划任务运行 此控制台应用程序写入日志文件 该日志文件在调试模式下运行时会创建并写入应用程序文件夹本身内的文件 但是 当它在任务计划程序中运行时 它会抛出一个错误 指出访
  • 在Linux中,找不到框架“.NETFramework,Version=v4.5”的参考程序集

    我已经设置了 Visual studio 来在我的 Ubuntu 机器上编译 C 代码 我将工作区 我的代码加载到 VS 我可以看到以下错误 The reference assemblies for framework NETFramewo
  • C# 存档中的文件列表

    我正在创建一个 FileFinder 类 您可以在其中进行如下搜索 var fileFinder new FileFinder new string C MyFolder1 C MyFolder2 new string
  • IQueryable 单元或集成测试

    我有一个 Web api 并且公开了一个端点 如下所示 api 假期 name name 这是 Web api 的控制器 get 方法 public IQueryable
  • 为什么这个二维指针表示法有效,而另一个则无效[重复]

    这个问题在这里已经有答案了 这里我编写了一段代码来打印 3x3 矩阵的对角线值之和 这里我必须将矩阵传递给函数 矩阵被传递给指针数组 代码可以工作 但问题是我必须编写参数的方式如下 int mat 3 以下导致程序崩溃 int mat 3
  • 保护 APK 中的字符串

    我正在使用 Xamarin 的 Mono for Android 开发一个 Android 应用程序 我目前正在努力使用 Google Play API 添加应用内购买功能 为此 我需要从我的应用程序内向 Google 发送公共许可证密钥
  • WPF DataGridTemplateColumn 组合框更新所有行

    我有这个 XAML 它从 ItemSource 是枚举的组合框中选择一个值 我使用的教程是 http www c sharpcorner com uploadfile dpatra combobox in datagrid in wpf h
  • 在屏幕上获取字符

    我浏览了 NCurses 函数列表 似乎找不到返回已打印在屏幕上的字符的函数 每个字符单元格中存储的字符是否有可访问的值 如果没有的话Windows终端有类似的功能吗 我想用它来替换屏幕上某个值的所有字符 例如 所有a s 具有不同的特征
  • 实体框架中的“it”是什么

    如果以前有人问过这个问题 请原谅我 但我的任何搜索中都没有出现 它 我有两个数据库表 Person 和 Employee 对每个类型的表进行建模 例如 Employee is a Person 在我的 edmx 设计器中 我定义了一个实体
  • 为boost python编译的.so找不到模块

    我正在尝试将 C 代码包装到 python 中 只需一个类即可导出两个函数 我编译为map so 当我尝试时import map得到像噪音一样的错误 Traceback most recent call last File
  • 是否可以在不连接数据库的情况下检索 MetadataWorkspace?

    我正在编写一个需要遍历实体框架的测试库MetadataWorkspace对于给定的DbContext类型 但是 由于这是一个测试库 我宁愿不连接到数据库 它引入了测试环境中可能无法使用的依赖项 当我尝试获取参考时MetadataWorksp
  • 如何使用 C++11 using 语法键入定义函数指针?

    我想写这个 typedef void FunctionPtr using using 我该怎么做呢 它具有类似的语法 只不过您从指针中删除了标识符 using FunctionPtr void 这是一个Example http ideone
  • 如何将十六进制字符串转换为无符号长整型?

    我有以下十六进制值 CString str str T FFF000 如何将其转换为unsigned long 您可以使用strtol作用于常规 C 字符串的函数 它使用指定的基数将字符串转换为 long long l strtol str
  • 不区分大小写的字符串比较 C++ [重复]

    这个问题在这里已经有答案了 我知道有一些方法可以进行忽略大小写的比较 其中涉及遍历字符串或一个good one https stackoverflow com questions 11635 case insensitive string

随机推荐