0

I would like to define an ostream operator to let me easily output variables of type alglib::complex. To provide a working example without including the alglib library I'll instead overload the output of complex<double> below (this clarification because of an earlier version of the question). In the header file "my_class.h" I have

using namespace std;
#include <complex>
#include <iostream>

class my_class {

    public:

    ostream& operator << (std::ostream& os, complex<double> a) {
        os << "(" << real(a) << "," << imag(a) << ")";
        return os;
    }

    void output(complex<double>);

    my_class() {}
    ~my_class() {}
};

And in the source file "my_class.cpp" I have

#include "my_class.h"

void my_class::output(complex<double> cd) {
    cout << cd << endl;
}

Finally I have a main method file "run_my_class.cpp":

#include "my_class.h"

int main(int argc, const char* argv[]) {

    my_class obj;
    complex<double> cd=complex<double>(1.0,-1.0);
    obj.output(cd);

}

I try to compile using

g++ -c my_class.cpp

but this gives me the error

my_class.h:9:62: error: ‘std::ostream& my_class::operator<<(std::ostream&, std::complex<double>)’ must take exactly one argument
 ostream& operator << (std::ostream& os, complex<double> a) {

However, if I define the operator as a friend, namely friend ostream& operator << (std::ostream& os, complex<double> a), it compiles and I compile the main method:

g++ run_my_class.cpp my_class.o -o run_my_class

And it works as it should. However this is not what it seems the friend keyword is for. Is there a better way to make this work?

jorgen
  • 3,425
  • 4
  • 31
  • 53
  • 1
    Why are you making the output operator a friend of the `my_class` class? You don't even use `my_class` in the functions? – Some programmer dude Oct 11 '15 at 11:56
  • 2
    The error almost sounds like no viable `operator <<` was found for the arguments, and the free rvalue-ref forwarder `operator<< (basic_ostream<..>&&, T const&)` was used instead. Please provide a [MCVE](http://stackoverflow.com/help/MCVE) with the appropriate context. – dyp Oct 11 '15 at 11:57
  • @JoachimPileborg So that the class can use the ostream operator.. I couldn't get it to conpile without `friend`. But maybe there's a better way? – jorgen Oct 11 '15 at 11:58
  • 1
    It is the other way around: you have to declare a function `friend` of a class, if the function uses private members of the class – 463035818_is_not_an_ai Oct 11 '15 at 12:06
  • 2
    maybe it would help if you show us the original problem – 463035818_is_not_an_ai Oct 11 '15 at 12:06
  • Please provide a minimal example. It's not even clear where that error happens. – Ulrich Eckhardt Oct 11 '15 at 12:30
  • thanks for comments, I'll update the answer to make it more clear – jorgen Oct 11 '15 at 12:33

2 Answers2

7

Since operator << will be called on an std::ostream, you cannot define this procedure as a member function for my_class, you have to define it as a global function, since it's an operation for std::ostream, not my_class.

By putting the friend keyword into the declaration, you are saying that you want to declare the operator << as a friend global function (not a member function!). The C++ standard lets you put the definition of the friend function there, but it won't be a member function. It is the same as the following, which is more clear:

#include <complex>
#include <iostream>

class my_class {

public:

    friend ostream& operator << (std::ostream& os, complex<double> a);

    void output(complex<double>);

    my_class() {}
    ~my_class() {}
};

std::ostream& operator << (std::ostream& os, complex<double> a) {
    os << "(" << real(a) << "," << imag(a) << ")";
    return os;
}

As it was already pointed out in the comments, the usage of friend is not necessary here.

Irrelevant to the question, but please be aware that resolving namespaces in a header file is generally a really-really bad idea, since all other files including it will implicitly resolve that namespace too. It can easily lead to vexing compilation errors in the long run.

mcserep
  • 3,231
  • 21
  • 36
  • Your use of the expressions "method" and "function" does not correspond to official C++ terminology. The correct ones would be "member function" and "global function". It is especially misleading and confusing to use the word "function" as if it did not (also) refer to member functions. "Method" is an *informally used* synonym for member functions. – Christian Hackl Oct 11 '15 at 13:15
  • @ChristianHackl Thanks for the comment, I revised my answer. Although I still think that the difference between method and function should not be confusing to anyone, these are general OOP terms, unrelated to a concrete language. Still, it's a C++ question, so you have your point. – mcserep Oct 11 '15 at 13:18
1

I wouldn't call it a better way but a more clear way.

Here's your stream operator again:

ostream& operator << (std::ostream& os, complex<double> a) {
        os << "(" << real(a) << "," << imag(a) << ")";
        return os;
}

Its first parameter is the output stream. Since you do not have access to the output stream, you can't use the output stream operator as a member function unless you make it a friend of the class.

If you want to want to avoid using friend you can always define it as a function external to the class, and that is the most common way.

dspfnder
  • 1,135
  • 1
  • 8
  • 13