【问题标题】:Using operators from different namespaces in std::find在 std::find 中使用来自不同命名空间的运算符
【发布时间】:2019-08-26 07:03:45
【问题描述】:

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

#include <vector>
#include <algorithm>

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

namespace bar{
    void func();
}

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

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

我的两个问题是:

  • 为什么第一个示例给出错误? (添加using后)
  • 如何解决? (不改变生成的代码)

编辑:

感谢 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);
}

【问题讨论】:

  • @LeonardoFaria 究竟是在哪里添加using语句?
  • 我将添加一个带有using 的sn-p 以便更好地理解
  • @LeonardoFaria - 谢谢!
  • 添加了sn-p(倒数第二个)
  • 第一种情况由于 ADL 而不起作用 - 编译器在命名空间 foo 而不是 foo::inner 中查找 operator==。在命名空间foo 中添加using inner::operator==

标签: c++ stl c++14


【解决方案1】:

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

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

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

  • 所有封闭的命名空间 - 但在这里搜索会在找到 any operator== 时停止。 (与您无关,但可能会绊倒那些只将 std 对象的运算符添加到全局命名空间中的人,例如 std::vector 的“支持”operator+)。

  • 执行 ADL - 搜索对象的命名空间(*it*value 的来源)以匹配 operator==

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

所以答案是:

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

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

【讨论】:

  • 但是添加using 语句肯定会将inner::operater== 添加到全局命名空间中。
  • @MartinBonner 在您放置using 的任何地方的范围内。这正是第二种情况起作用的原因。但它不会神奇地让它在std::find 的内脏范围内。
猜你喜欢
  • 1970-01-01
  • 2011-12-03
  • 2019-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-26
  • 1970-01-01
  • 2012-03-07
相关资源
最近更新 更多