c++c++17std-variant

Why can't std::variant find operator<() when not in same namespace as compared classes


I was trying to provide a custom operator< for a class from an external library. This class is within that library's namespace, however, the operator I wanted to define is not. Now if I define a std::variant and want to use it in a std::set, the compilation fails as it can't detect the operator<.

Here's an example (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;
}

If you put the operator<s in the namespace myClasses it compiles fine.

Can someone explain to me, why my original attempt failed? If I just compare myClasses::classA(1) < myClasses::classA(2), there's no need to put the operators in the myClasses namespace.


Solution

  • This is an feature of argument dependent lookup (ADL), which you are relying on when the operator is search for from std::variant.

    When searching for free functions, including overloaded operators, the compiler will only search in namespaces related to the arguments to the function in question.

    There are more details in this cppreference article.

    Where you call the comparison directly from your code, at the same namespace scope as the operator< declarations, "normal" (i.e. non-ADL) lookup can find the operator definition directly.