在 std::find 中使用来自不同命名空间的运算符
Using operators from different namespaces in std::find
我有以下自动生成的代码:
#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);
}
问题是参数相关查找 (ADL)。
在std::find
模板中的某个地方,有一个if (*it == value)
,其中value
和it
是依赖类型。这意味着编译器将等到模板实例化后再查找要使用的正确operator==
。
但是它查找operator==
的位置或多或少仅限于(没有太深入地了解非限定名称查找的细节):
-
所有封闭的命名空间 - 但在此处搜索停止查找任何
operator==
。(与您无关,但可能会绊倒只是添加运算符的人,例如std
对象到全局命名空间中,例如"支持"operator+
forstd::vector
)。 -
执行 ADL - 搜索对象的命名空间(
*it
和*value
来自何处)以查找匹配的operator==
。
但是您要使用的operator==
无法以这种方式找到 - 它位于不同的(更深的)命名空间中。这基本上是生成的代码中的一个错误 -运算符应始终驻留在与他们操作的对象所在的命名空间相同的命名空间中。
所以答案是:
-
找不到
operator==
,因为它位于错误的命名空间中。 -
这里没有问题,因为在 lambda 中找到了正确的运算符,
std::find_if
只是直接使用 lambda(根本没有查找)。
- 通过继承类使用来自不同命名空间的运算符
- 在 C++17 中的命名空间和子命名空间中重载运算符是不明确的
- 在类设计中查找外部命名空间中的重载运算符
- 重载运算符 + 用于向量:命名空间标准
- 为什么 std::variant 找不到运算符<() 当与比较类不在同一命名空间中时
- 如何为缺少预定义运算符而不扩展命名空间"std"的标准类型定义运算符>> (istream &, ...)?
- C++命名空间、内部类和运算符解析
- 运算符<<依赖于参数的查找不在全局命名空间中查找
- 为什么找不到使用命名空间中定义的类型实例化的 std::weak_ptr 的重载运算符==?
- 在命名空间内的类中使用带有运算符重载的字符串流时"no match for ‘operator>>’"
- 在命名空间内的 lambda 中使用时未找到运算符重载
- 如何在命名空间中引用用户定义的文本运算符
- 为命名空间中的类重载运算符<<时发出警告
- 为在与类方法中的类相同的命名空间中定义的结构调用重载运算符
- 在 std::find 中使用来自不同命名空间的运算符
- 在全局命名空间中重载不依赖于用户定义类型的标准定义类型的运算符是否格式正确?
- 为什么命名空间中的函数看不到全局定义的运算符<<?
- 基于 SFINAE 的跨命名空间的运算符重载
- 如何在不同的命名空间中指定重载运算符
- 如何使 [std::运算符 " " s] 在命名空间中可见?