Argument-dependent search leading unexpectedly to types, alias from another namespace

I just came across an interesting behavior with a search argument dependent, which I don't quite 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 realized that c::Foo is actually b::Baz<...> , so it makes some sense that ADL finds a statement when I define it inside namespace b . But it seems uninteresting that the statement definition inside namespace c does not work, since c::Foo should (IMHO) allow the compiler to execute ADL inside namespace c .

Why is this not so? What is the meaning of this?

+6
source share
1 answer

[basic.lookup.argdep] / 2 :

Typedef names and use-declarations used to indicate types do not contribute to this set.

Neither typedef names nor declaration declarations are associated with the type that they denote. If they were (which would actually be contradictory, IMO), everything could very easily break; simply because I printed some class, all calls now consider functions added to the typedef neighborhood that are almost never needed:

 #include <string> namespace A { using str = std::string; int stoi(str); // This will be a candidate in eg stoi(std::string{"0.4"}), // leading to potentially different behavior or ambiguity namespace B { int stoi(std::string); // This is no candidate, because...? } 
+4
source

All Articles