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.
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.