Explanation
Since operator<<
is being called in an unqualified manner from inside namespace std (more specifically inside std::ostream_iterator), and all the arguments involved are also declared in the same namespace, only namespace std
will be searched for potential matches.
Hackish solution
namespace std {
template<typename t1, typename t2>
std::ostream& operator<<(std::ostream& os, const std::pair<t1, t2>& pair)
{
return os << "< " << pair.first << " , " << pair.second << " >";
}
}
Note: You can only specialize templates that includes user-defined types inside namespace std
, the above snippet is therefore potentially ill-formed according to the Standard (if std::pair<T1,T2>
isn't a user-declared type, see this discussion).
Detailed explanation
Below we have namespace N which will aid us in trying to simulate your usage of namespace std, and what is going on when the compiler tries to find a suitable overload for a given type.
namespace N
namespace N {
struct A { };
struct B { };
void func (A value) { std::cout << "A"; }
template<class T>
void call_func (T value) { func (value); }
}
main.cpp
void func (N::B value) {
std::cout << "B";
}
int main() {
N::A a;
N::B b;
func (a); // (1)
func (b); // (2)
N::call_func (a); // (3a)
N::call_func (b); // (3b)
}
Notes:
Without knowing about Argument-dependent lookup, one might be surprised that the compiler is able to find the suitable overload required to make (1) work.
ADL states that upon using an unqualified-name in a function call, not only is the current namespace searched for suitable overloads, the namespace of the arguments are also searched; and this is how the compiler finds N::func
, even though we didn't write so explicitly.
We have a suitable overload in the current namespace; it's all good in the hood.
...
Why does (3a) compile, whereas (3b) will result in a nasty diagnostic?
When we instantiate the template N::call_func<T>
it will try to pass on the argument of type T
to the unqualified function named func
.
Since the rules of name-lookup says that the current namespace, and the namespace of the arguments involved, are searched for suitable matches in case we are calling a function from a unqualified name, it will only search namespace N if T
is a type declared in namespace N.
Both N::A
and N::B
are declared in namespace N, so the compiler will not search any other scope to find a suitable overload; which is why lookup fails.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…