Home > Software engineering >  std::ostream operator implementation for a type
std::ostream operator implementation for a type

Time:11-13

Why is the reason of almost always, declare the ostream operator as a friend function, and not as a member function or as a free function? What benefits have to choose to implement it as a friend compared with the alternatives?

CodePudding user response:

A member function doesn't work here, because it requires the lhs to be of the enclosing class type, while you need it to be ostream.

A free function would work, but it opens you up to some confusing overload resolution. A friend function behaves the same way regardless of whether caller is in the same namespace as the class (or has using namespace for it), because either way it can only be found via ADL. (I'm assuming the operator is in the same namespace as the class.)

But a free function can be found without ADL, but only if you're in the same namespace. When found without ADL, it can tolerate some implicit conversions of the rhs, which wouldn't work with ADL.

Example:

#include <iostream>

struct AA {};
struct BB {};

namespace N
{
    struct A
    {
        A(AA) {}

        template <typename T, typename U>
        friend std::basic_ostream<T,U> &operator<<(std::basic_ostream<T,U> &o, A) {return o;}
    };

    struct B
    {
        B(BB) {}
    };

    template <typename T, typename U>
    std::basic_ostream<T,U> &operator<<(std::basic_ostream<T,U> &o, B) {return o;}
}

int main()
{
    {
        std::cout << AA{}; // error
        std::cout << BB{}; // error
    }

    {
        using namespace N;
        std::cout << AA{}; // error
        std::cout << BB{}; // ok
    }
}
  •  Tags:  
  • c
  • Related