问题
Compiling the following code fails because the second function can't find the first one, even though it's outside namespaces. I couldn't figure out the problem myself, and so far I haven't found any answers on the net.
test.cpp:
#include <bits/stdc++.h>
struct myclass {};
template <typename T, typename U>
std::ostream& operator<< (std::ostream &os, const std::pair<T, U> &p) {
os << "(" << p.first << ", " << p.second << ")";
return os;
}
namespace my {
void operator<< (std::ostream os, myclass m) {
std::cout << std::pair<int, int>(5, 4); // This is line 13.
}
}
int main() {
return 0;
}
Error given by the compiler (g++ test.cpp -O2 -o test.exe
):test.cpp:13:13: error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'std::pair<int, int>')
.
And it goes on, giving a long list of suggestions for what operator<<
could have meant.
Observation 1: If the two functions differ in name, no error occurs.
Observation 2: If namespace my {
}
is removed, no error occurs.
回答1:
This is a kind of name hiding; functions/operators can't be overloaded through different scopes.
According to the rule of name lookup,
(emphasis mine)
..., name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.
For this case, the name operator<<
is found at the scope of namespace my
(i.e. itself), then name lookup stops, the global scope won't be examined, the global operator<<
won't be considered for the following overload resolution.
And
Observation 1: If the two functions differ in name, no error occurs.
It's fine because there's no name hiding.
Observation 2: If namespace my { } is removed, no error occurs.
It's fine because the two operator<<
is put at the same scope, i.e. the global namespace. Then both operator<<
could be found and then considered at overload resolution, the appropriate one will be selected at last.
As the comments suggested, you can apply using
to introduce the names in global namespace into namespace my
; then both operator<<
will be found and then considered in overload resolution.
回答2:
The operator<<
defined in namespace my
prevents overload resolution to consider your operator<<
defined in the global namespace. You can only rely on ADL here or bring the desired overload in the current scope:
namespace my {
std::ostream& operator<<(std::ostream& os, myclass m) {
// Bringing the operator in the global namespace in the current scope
using ::operator<<;
std::cout << std::pair<int, int>(5, 4);
}
}
来源:https://stackoverflow.com/questions/54829319/c-cant-find-function-out-of-namespace