Why can't I overload this statement in the same namespace as the structure?

I have the following code:

#include <iostream> #include <vector> namespace X { std::ostream& operator<<(std::ostream& os,const std::vector<double>& v){ for (int i=0;i<v.size();i++){os << v[i] << " ";} return os; } namespace Y { struct A {std::vector<double> x;}; std::ostream& operator<<(std::ostream& os,const A& a){ os << ax << std::endl; return os; } } } using namespace X; int main(int argc, char** argv) { std::vector<double> v(10,0); std::cout << v << std::endl; Y::A a; std::cout << a << std::endl; return 0; } 

The first overload works, and the second does not. For some reason, he cannot find the first one. I get an error message:

 no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'const std::vector<double>') os << ax << std::endl; ^ 

I do not understand why I am getting this error. For example, something like this seems completely valid:

 namespace A { void foo(){} namespace B { void bar(){foo();} } } 

However, the only way to fix the above problem was to put the second overload also in X. Why is it impossible to have it in the same namespace as the structure (ie X :: Y)?

PS: I read on ADL and I found some related questions (like this and, but what I understood by reading this should work.

+6
source share
3 answers

In the Depend Lookup (or Koenig Lookup) argument, the compiler adds to the scope all the characters declared in the parent areas of each parameter .

Even if Y is the "child namespace" of X , they are not related in ADL terms. The first of your parameters is the type defined in the std:: , and the second is a local character (defined in the same namespace as the function itself).

Note that due to the reasons mentioned above, you are most likely to get another error on this line:

 std::cout << v << std::endl; 

when the compiler cannot find operator<< overloaded for std::vector<double> (because it lies inside namespace X ).

To solve this problem you can use:

 using X::operator<< 

inside namespace Y or move this overload.

If you are wondering why the foobar example works: because ADL ( Argument dependent search) concerns the parameter area of ​​the functions, not the functions themselves. In foobar ADL code is not used.

+2
source

As in the other answers, I ultimately deduced that the ADL of the <operator is hindered by the fact that it passed inside another operator <

Lesson today: always write the <<overload operator in terms of the recording method :)

Here's the fix:

 #include <iostream> #include <vector> namespace X { std::ostream& operator<<(std::ostream& os,const std::vector<double>& v){ for (int i=0;i<v.size();i++){os << v[i] << " ";} return os; } namespace Y { struct A { std::vector<double> x; void write(std::ostream&os) const { os << x << std::endl; } }; std::ostream& operator<<(std::ostream& os,const A& a) { a.write(os); return os; } } } using namespace X; int main(int argc, char** argv) { std::vector<double> v(10,0); std::cout << v << std::endl; X::Y::A a; std::cout << a << std::endl; return 0; } 
+2
source

The easiest way is this: To overload a function, the overloaded version must live in the same nemaspace, otherwise it is a completely different function. A function name (for the compiler) is the full path from the global namespace to the function itself.

 ::function_at_global_namespace(); Namespace::function_name(); // Some funtion within a namespace; Namespace_1::function_name(); // Some other function within another namespace; 

So,

Standar std::ostream& operator<< lives in the std , you do not overload this operator by simply defining anotherone in the X namespace.

As pointed out by @ 0x499602D2, you must use X::operator<< in the Y namespace to invoke this version of the operator.

std::ostream& std::operator<< and std::ostream& X::operator<< are different functions.

In the following code, none of the foo versions overloads.

 // What version of foo gets called? A::foo, or B::foo? namespace A { void foo(){cout << "A::foo" << endl;} namespace B { void foo(){ cout << "B::foo" << endl;} void bar(){foo();} } } namespace C { void foo(int a) { cout << "C:foo" << endl; } } 
+1
source

Source: https://habr.com/ru/post/986673/


All Articles