What operators should be declared as friends?

This really depends on whether a class is going to be on the left- or right-hand side of the call to operator== (or other operator). If a class is going to be on the right-hand side of the expression—and does not provide an implicit conversion to a type that can be compared with the left-hand side—you need to implement operator== as a separate function or as a friend of the class. If the operator needs to access private class data, it must be declared as a friend.

For example,

class Message {
    std::string content;
public:
    Message(const std::string& str);
    bool operator==(const std::string& rhs) const;
};

allows you to compare a message to a string

Message message("Test");
std::string msg("Test");
if (message == msg) {
    // do stuff...
}

but not the other way around

    if (msg == message) { // this won't compile

You need to declare a friend operator== inside the class

class Message {
    std::string content;
public:
    Message(const std::string& str);
    bool operator==(const std::string& rhs) const;
    friend bool operator==(const std::string& lhs, const Message& rhs);
};

or declare an implicit conversion operator to the appropriate type

class Message {
    std::string content;
public:
    Message(const std::string& str);
    bool operator==(const std::string& rhs) const;
    operator std::string() const;
};

or declare a separate function, which doesn't need to be a friend if it doesn't access private class data

bool operator==(const std::string& lhs, const Message& rhs);

When you have your operators outside the class, both parameters can participate in implicit type conversions (whereas with operators being defined in the class body, only the right-hand operands can). Generally, that's a benefit for all the classic binary operators (i.e. ==,!=, +, -, <<, ... ).

Of course you should only declare operators friends of your class if you need to and not if they compute their result solely based on public members of the class.