Question

Can the following code (I only kept the relevant part) be converted to use a static member function rather than a friend free function? If not, why not? I tried to convert it to use a static member function in multiple different ways and failed (kept getting different compiler errors for different variations), but I gathered from the answer to this question that you could use either one to do the same things. Is this not technically true due to some property of C++ syntax? Where am I going wrong here?

class Tape {
    public:
        friend std::ostream &operator<<(std::ostream &, Tape &);

    private:
        char blank;
        size_t head;
        std::string tape;
}


std::ostream &operator<<(std::ostream &out, Tape &tape) {
    out << tape.tape << std::endl;
    for (size_t i = 0; i < tape.head; i++)
        out << ' ';
    out << '^' << std::endl;
    return out;
}
Was it helpful?

Solution

According to the C++ Standard

6 An operator function shall either be a non-static member function or be a non-member function and have at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration.

So you may not define operator << as a static mamber function of the class. Nevertheless inside the definition of the operator you may use static member functions. For example

#include <iostream>

class A
{
private:
    int x = 10;
public:
    static std::ostream & out( std::ostream &os, const A &a )
    {
        return ( os << a.x );
    }
};

std::ostream & operator <<( std::ostream &os, const A &a )
{
    return ( A::out( os, a ) );
}

int main() 
{
    A a;
    std::cout << a << std::endl;

    return 0;
}

Opposite to C++ in C# operator functions are defined as static.:)

OTHER TIPS

Since the std::ostream argument is the left hand side of the operator, it can't be a member of your class (static or otherwise).

So it has to be a free function, because you can't add members to std::ostream.

It doesn't have to be a friend though, it could instead call a public member.
I personally prefer this method, as it doesn't expose anything to the outside.

class Tape {
    public:
    void print(std::ostream &out) const 
    {
        out << tape << std::endl;
        for (size_t i = 0; i < head; i++)
            out << ' ';
        out << '^' << std::endl;
    }
};


std::ostream& operator<<(std::ostream &out, const Tape &tape) 
{
    tape.print(out);
    return out;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top