Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why I cannot put this operator overload in the same namespace as the struct?

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 << a.x << 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, but the second one does not. For some reason it cannot find the first one. I get the error:

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

I do not understand why I get this error. For example something like this seems to be 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 not possible to have it in the same namespace as the struct (ie. X::Y)?

PS: I was reading on ADL and I found some related questions (e.g. this and this, but what I understood from reading this, the above should work.

like image 218
463035818_is_not_a_number Avatar asked May 06 '15 15:05

463035818_is_not_a_number


People also ask

Why we Cannot overload dot operator?

These operators cannot be overloaded because if we overload them it will make serious programming issues. For an example the sizeof operator returns the size of the object or datatype as an operand. This is evaluated by the compiler.

Can we overload == operator in C++?

You can redefine or overload the function of most built-in operators in C++. These operators can be overloaded globally or on a class-by-class basis. Overloaded operators are implemented as functions and can be member functions or global functions.

Can we overload only existing operator?

Rules for Operator Overloading:You can only overload existing operators. You can't overload new operators. Some operators cannot be overloaded using a friend function. However, such operators can be overloaded using member function.

Can we overload insertion operator?

Input/Output Operators Overloading in C++ C++ is able to input and output the built-in data types using the stream extraction operator >> and the stream insertion operator <<. The stream insertion and stream extraction operators also can be overloaded to perform input and output for user-defined types like an object.


2 Answers

In Argument Depended Lookup (or Koenig Lookup), compiler adds to the scope of visibility all symbols declared in parent scopes of each parameter.

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

Note, that because of reasons mentioned above, you will most likely get another error in this line:

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

when compiler will not be able to find operator<< overloaded for std::vector<double> (because it lies inside namespace X).

To solve this, you can use:

using X::operator<<

inside namespace Y or move that overload.

If you are wondering, why foobar example works: that's because ADL (Argument Dependent Lookup) is about scope of parameters of functions, not functions themselves. In foobar code, ADL isn't applied.

like image 60
Mateusz Grzejek Avatar answered Oct 13 '22 12:10

Mateusz Grzejek


As per other answers, I eventually deduced that ADL of operator<< was being impeded by the fact that it was taking place inside another operator<<.

Today's lesson: always write an operator<< overload in terms of a writer 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;
}
like image 23
Richard Hodges Avatar answered Oct 13 '22 14:10

Richard Hodges