0

In C++ is there a way to use the insertion operator for a class method?

This operator<< overload is working:

class Complex {
public:
  //Normal overload:
  friend std::ostream& operator<<(std::ostream &out, const Complex &o) {
    out << "test overload";
    return out;
  }

  Complex() {};
  ~Complex() {};
};

I can do this:

int main()
{
  Complex* o = new Complex();

  std::cout << "This is test: " << *o << "." << std::endl; // => This is test: test overload.
}

I know about stream manipulators, like this:

std::ostream& welcome(std::ostream& out)
{
    int data = 1;
    out << "WELCOME " << data << "\r\n";
    return out;
}

int main()
{
  std::cout << "Hello " << welcome; // => "Hello WELCOME 1\r\n"
}

How can I put the welcome method into the Complex class and then how shall I call it from cout (please note that welcome method must access some class member variables)?

My trial:

class Complex {
public:
  //Normal overload:
  friend std::ostream& operator<<(std::ostream &out, const Complex &o) {
    out << "test overload";
    return out;
  }

  std::ostream& welcome(std::ostream& out) {
    out << "WELCOME " << data << "\r\n";
    return out;
  }

  Complex() { data = 1; };
  ~Complex() {};
private:
  int data;
};

int main()
{
  Complex* o = new Complex();

  std::cout << "This is test2: " << o->welcome << std::endl; // compile error
}
Daniel
  • 1,453
  • 13
  • 33
  • 3
    Please show real code. Your "normal" overload is a member function and cannot work like this – 463035818_is_not_a_number May 28 '20 at 19:22
  • 1
    `mymethod` could return a string then you can do `std::cout << c.mymethod() << " then other stuff"`. Please clarify, its not really clear what your problem is – 463035818_is_not_a_number May 28 '20 at 19:25
  • 1
    What exactly would be the intended output of your program? – mrksngl May 28 '20 at 19:25
  • You could write a custom manipulator to achieve such an effect. https://accu.org/index.php/journals/1769 – john May 28 '20 at 19:27
  • I think I've answered all the questions in the update. @idclev463035818: returning a string is not good, because the method shall also utilize the stream and insert more items. – Daniel May 29 '20 at 06:09
  • Yes, for the initial I wrote from head. Sorry for that. I left there for historic reasons. – Daniel May 29 '20 at 06:14
  • 1
    you do not have to leave it there for history, you also do not have to add "UPDATE" to your question. If someone wants to see the edit history, they can do so here: https://stackoverflow.com/posts/62072866/revisions – 463035818_is_not_a_number May 29 '20 at 06:15
  • there can be arguments against returning a string from the method but I do not understand yours. You can get the desired output when `extrainfo` returns a string – 463035818_is_not_a_number May 29 '20 at 06:17
  • your example was better before. Now the welcome method does nothing but pipe a single string into the stream. Anyhow, hope the answer helps. Will add some more on why yours doesnt work – 463035818_is_not_a_number May 29 '20 at 06:25
  • @idclev463035818: extrainfo will concat a lot of components with <<. approach.="" i="" keep="" like="" stream-based="" that="" the="" to="" why=""> – Daniel May 29 '20 at 06:25
  • btw I suggest you to read this: https://stackoverflow.com/questions/6500313/why-should-c-programmers-minimize-use-of-new There is no reason to use `new` in your code and you are leaking memory – 463035818_is_not_a_number May 29 '20 at 06:31

1 Answers1

2

One easy way to pick a different << overload is to use a different type.

#include <iostream>

class Complex {
public:
  //Normal overload:
  friend std::ostream& operator<<(std::ostream &out, const Complex &o) {
    out << "test overload";
    return out;
  }

  struct extra_info {
      const Complex& parent;
      extra_info(const Complex& p) : parent(p) {}
      friend std::ostream& operator<<(std::ostream& out, const extra_info& ei){
        int i = 1;
        out << "extrainfo " << i;
        return out;
      }
  };
  extra_info extrainfo() {
      return {*this};
  }

  Complex() {};
  ~Complex() {};
};


int main() {
    Complex c;
    std::cout << c << "\n";
    std::cout << c.extrainfo();
}

Output:

test overload
extrainfo 1

I suppose in your real code you are using members. Hence the helper type must hold a reference to the Complex instance.

463035818_is_not_a_number
  • 64,173
  • 8
  • 58
  • 126
  • hmm.. could we get rid of warning by using non-recursive manipulator? Not like we need an argument in case of nested class. Or one can remove name of `ei` argument – Swift - Friday Pie May 29 '20 at 06:32
  • `c.welcome(std::cout)` fails compiling on my machine: "error: cannot bind ‘std::ostream {aka std::basic_ostream}’ lvalue to ‘std::basic_ostream&&’" – Daniel May 29 '20 at 06:33
  • @Swift-FridayPie sorry I dont understand. I get no warning and there is no recursion – 463035818_is_not_a_number May 29 '20 at 06:34
  • @Daniel sorry you changed the code to quickly and I got lazy do write the answer carefully, my fault, I will just remove it – 463035818_is_not_a_number May 29 '20 at 06:35
  • @idclev463035818: I'm interested in your oppinion: this extrainfo solution is theoretically better (faster to run) than creating a stringstream and returning it for cout? – Daniel May 29 '20 at 06:39
  • @Daniel I dont understand what you mean. It is less expensive than constructing a string and printing that. Not sure, but the compiler will likely optimize the `extra_info` away. If you care about performance you need to look at the output of the compiler, but don't do premature optimization, code is primarily written to be read by humans and you should write code to be readable – 463035818_is_not_a_number May 29 '20 at 06:46
  • @Daniel btw never listen to "opinions" about performance. Compiler optimizations are an extremely involved process and naive expectations are too often completely off. – 463035818_is_not_a_number May 29 '20 at 06:49
  • Thx. Is there any way to use private members of *Compex* class when constructing extrainfo? – Daniel May 29 '20 at 06:56
  • @Daniel you can make `extra_info` a friend of `Complex`. Dont remember atm, maybe nested classes already have access to privates, but I might be completely wrong – 463035818_is_not_a_number May 29 '20 at 06:58