I just ran into some interesting behavior with argument-dependent lookup, which I do not fully understand:
#include <iostream>
namespace a {
struct Foo {
Foo(int v1, int v2) : v1(v1), v2(v2) { }
int v1,v2;
};
}
namespace b {
template <typename T>
struct Baz : T {
using T::T;
};
}
namespace c {
using Foo = ::b::Baz< ::a::Foo>;
// (1) NOT FOUND BY ADL
// std::ostream& operator << (std::ostream& os, const Foo& foo)
// {
// return os << foo.v1 << "," << foo.v2;
// }
}
namespace b {
// (2) FOUND BY ADL
std::ostream& operator << (std::ostream& os, const ::c::Foo& foo)
{
return os << foo.v1 << "," << foo.v2;
}
}
int main()
{
c::Foo foo(1,2);
// Variant (1): ADL fails: should it not find
// c::operator<<(std::ostream&, const Foo&) ?
// Variant (2) compiles
std::cout << "foo: " << foo << std::endl;
}
I get that c::Foo
is actually b::Baz<...>
, so it somewhat makes sense that ADL finds the operator when I define it inside namespace b
. But it seems to defy intuition that defining the operator inside namespace c
does not work, since c::Foo
should (IMHO) allow the compiler to perform ADL inside namespace c
as well.
Why is that not the case? What is the rationale behind this?