为什么 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)查找可以直接找到运算符定义。