为什么 std::variant 与比较 类 不在同一个命名空间时找不到 operator<()
Why can't std::variant find operator<() when not in same namespace as compared classes
我试图为来自外部库的 class 提供自定义 operator<
。 class 在该库的命名空间内,但是,我想定义的运算符不在。现在,如果我定义一个 std::variant
并想在 std::set
中使用它,编译将失败,因为它无法检测到 operator<
。这是一个例子 (godbolt):
#include <variant>
#include <set>
#include <string>
namespace myClasses
{
struct classA
{
classA(const unsigned int i) :i(i) {};
int i;
};
struct classB
{
classB(const unsigned int u) :u(u) {};
unsigned int u;
};
}// namespace myClasses
//namespace myClasses { //<- uncomment this
bool operator<(const myClasses::classA &v, const myClasses::classA &w)
{
return v.i < w.i;
}
bool operator<(const myClasses::classB &v, const myClasses::classB &w)
{
return v.u < w.u;
}
//} //<- and uncomment this
using var_t = std::variant<myClasses::classA, myClasses::classB>;
int main()
{
std::set<var_t> myset;
myset.emplace(myClasses::classB(1));
myset.emplace(myClasses::classA(2));
return 0;
}
如果将 operator<
放在命名空间 myClasses
中,它可以正常编译。
有人可以向我解释一下,为什么我最初的尝试失败了吗?如果我只是比较
myClasses::classA(1) < myClasses::classA(2)
,无需将运算符放在 myClasses
命名空间中。
非常感谢您。
这是参数相关查找 (ADL) 的一项功能,您在从 std::variant
.
中搜索运算符时依赖于它
搜索自由函数(包括重载运算符)时,编译器将仅在与相关函数的参数相关的名称空间中搜索。
this cppreference article中有更多详细信息。
如果您直接从代码中调用比较,在与 operator<
声明相同的命名空间范围内,"normal"(即非 ADL)查找可以直接找到运算符定义。
我试图为来自外部库的 class 提供自定义 operator<
。 class 在该库的命名空间内,但是,我想定义的运算符不在。现在,如果我定义一个 std::variant
并想在 std::set
中使用它,编译将失败,因为它无法检测到 operator<
。这是一个例子 (godbolt):
#include <variant>
#include <set>
#include <string>
namespace myClasses
{
struct classA
{
classA(const unsigned int i) :i(i) {};
int i;
};
struct classB
{
classB(const unsigned int u) :u(u) {};
unsigned int u;
};
}// namespace myClasses
//namespace myClasses { //<- uncomment this
bool operator<(const myClasses::classA &v, const myClasses::classA &w)
{
return v.i < w.i;
}
bool operator<(const myClasses::classB &v, const myClasses::classB &w)
{
return v.u < w.u;
}
//} //<- and uncomment this
using var_t = std::variant<myClasses::classA, myClasses::classB>;
int main()
{
std::set<var_t> myset;
myset.emplace(myClasses::classB(1));
myset.emplace(myClasses::classA(2));
return 0;
}
如果将 operator<
放在命名空间 myClasses
中,它可以正常编译。
有人可以向我解释一下,为什么我最初的尝试失败了吗?如果我只是比较
myClasses::classA(1) < myClasses::classA(2)
,无需将运算符放在 myClasses
命名空间中。
非常感谢您。
这是参数相关查找 (ADL) 的一项功能,您在从 std::variant
.
搜索自由函数(包括重载运算符)时,编译器将仅在与相关函数的参数相关的名称空间中搜索。
this cppreference article中有更多详细信息。
如果您直接从代码中调用比较,在与 operator<
声明相同的命名空间范围内,"normal"(即非 ADL)查找可以直接找到运算符定义。