首页 > 解决方案 > 在 std::find 中使用来自不同命名空间的运算符

问题描述

我有以下自动生成的代码:

#include <vector>
#include <algorithm>

namespace foo{  
    struct S{};
    namespace inner{
        bool operator==(const S&,const S&){return true;}
    }
}

namespace bar{
    void func();
}

S我现在想使用 STL 的find算法在容器中搜索对象:

void bar::func(){
    std::vector<foo::S> v;
    foo::S s;
    std::find(v.begin(),v.end(),s);
}

但是我收到此错误:

/opt/compiler-explorer/gcc-8.3.0/include/c++/8.3.0/bits/predefined_ops.h:241:17:
error: no match for 'operator==' (operand types are 'foo::S' and 'const foo::S')

  { return *__it == _M_value; }

即使添加后,using foo::inner::operator==;我也会收到相同的错误:

void bar::func(){
    using foo::inner::operator==;
    std::vector<foo::S> v;
    foo::S s;
    std::find(v.begin(),v.end(),s);
}

但是,当我这样做时,它会起作用:

void bar::func(){
    std::vector<foo::S> v;
    foo::S s;
    std::find_if(v.begin(),v.end(),[s](foo::S e){
        using foo::inner::operator==;
        return s==e;
    });
}

我的两个问题是:

编辑:

感谢 Max 的回答(https://stackoverflow.com/a/55517500/8900666),我找到了解决此问题的方法(有点难看但有效):

// Generated code
#include <vector>
#include <algorithm>

namespace foo{  
    struct S{};
    namespace inner{
        bool operator==(const S&,const S&){return true;}
    }
}
namespace bar{
    void func();
} 

// My code
namespace foo{
    using inner::operator==;
}

void bar::func(){
    std::vector<foo::S> v;
    foo::S s;
    std::find(v.begin(),v.end(),s);
}

标签: c++stlc++14

解决方案


问题是参数相关查找(ADL)。

std::find模板中的某处,有一个if (*it == value)、 wherevalueit是依赖类型。这意味着编译器将等到模板被实例化后才寻找正确operator==的使用方法。

但它查找的地方operator==或多或少限于(无需深入了解不合格名称查找的细节):

  • 所有封闭的名称空间 - 但在此处搜索会在找到任何 operator==. (与您无关,但可能会绊倒那些只是将例如std对象的运算符添加到全局名称空间中的人,例如“支持” operator+for std::vector)。

  • 执行 ADL - 搜索对象的名称空间(从哪里*it和从哪里来*value)以查找匹配的operator==.

但是operator==无法以这种方式找到您要使用的 - 它位于不同的(更深的)命名空间中。这基本上是生成的代码中的一个错误 -运算符应该始终位于与定义它们操作的对象相同的命名空间中。

所以答案是:

  1. operator==找不到您的,因为它位于错误的命名空间中。

  2. 这里没有问题,因为在 lambda 中找到了正确的运算符,并且std::find_if直接使用 lambda(根本没有查找)。


推荐阅读