Edit: I just saw the answer by @n. m. could be an AI. He show how to create an I/O manipulator without an argument! I thought it could not be done. There is still a lot of good information below, however, so, read on, as you wish.
The OP is trying to code an I/O manipulator that does not take an argument, and use it to output the members of a class. The first part of this answer explains why that won't work [unless, that is, you take a different tack, and use the method of n. m.]. You have to use a manipulator with an argument in order to achieve the OP's goal. The second part of the this answer explains how to do that.
The other answers posted here do not use the forward declaration, nor the extra friend declaration, used by this answer. [Except for the answer by n. m.,] that means that the I/O manipulators they define can only access the public members of class myClass. This answer shows how to get access to the private members.
I/O Manipulators with no arguments
I/O manipulators, such as std::boolapha, are functions that take a stream reference as their only argument.
It is as though boolalpha (for output streams) had the following definition:
std::ostream& boolalpha( std::ostream& ost) { // Set the appropriate format flag, and then... return ost; }
Note that this is not how boolapha is actually implemented. It is, however, how you can implement your own manipulator:
std::ostream& myManipulator( std::ostream& ost) { // Use `ost` in some way, either by outputting something, // or by modifying its settings. Then... return ost; }
When you insert a manipulator that takes no arguments into a stream, you invoke operator<< with the address of the manipulator function.
std::cout << myManipulator; // Uses the address of function `myManipulator`
This works because there are special overloads of operator<< that are defined precisely to match the signatures of functions like myManipulatr. Those are part of the Standard Library. You do not have to write them.
Let's try it.
// main.cpp #include <iomanip> #include <iostream> std::ostream& myManipulator(std::ostream& ost) { ost << "myManipulator sets the width to 25, and the fill character to '*'.\n" << std::setfill('*') << std::setw(25); return ost; } int main() { std::cout << myManipulator << 42 << '\n'; return 0; } // end file: main.cpp
Output:
myManipulator sets the width to 25, and the fill character to '*'. ***********************42
No room for the this pointer
Given the mechanics described above, there is no mechanism for passing the this pointer in an I/O manipulator that does not take any arguments.
You might try coding your own operator<< overload that takes a pointer to a member function as its argument, but that won't work. A pointer-to-member can only be invoked by providing an object.
Here is what they say at isocpp.org
In C++, member functions have an implicit parameter which points to the object (the this pointer inside the member function). Normal C functions can be thought of as having a different calling convention from member functions, so the types of their pointers (pointer-to-member-function vs pointer-to-function) are different and incompatible. C++ introduces a new type of pointer, called a pointer-to-member, which can be invoked only by providing an object.
It is not possible, therefore, to create the I/O manipulator described in the OP [unless, that is, you use the very different method of n. m.].
But don't despair. You can create a manipulator that takes an argument.
An I/O manipulator with an argument
For this example, we give myClass two string variables. One should be output when detail is requested. Otherwise, the regular string should be output. Both are private.
Note the forward declaration of class detailed. That's needed for the second operator<< function, which takes a reference to a detailed object as one of its arguments.
class detailed; class myClass { std::string regular{ "Regular: no detail" }; std::string detail{ "Detailed: too much information" }; public: friend std::ostream& operator<< (std::ostream& ost, myClass const& mc) { // Call this function for "regular" output. ost << mc.regular; return ost; } // The friend declaration below is the only modification you need to // make in `myClass`. Friendship give access to the private members, // so you don't need to clutter `myClass` with debugging details used // for "detailed" output. friend std::ostream& operator<< (std::ostream& ost, detailed const& d); };
Next, define class detailed, which holds a reference to a myClass object. We are using const&, because we don't want the I/O manipulator to modify a myClass object. Class detailed uses the hidden friend idiom to define the operator<< function used for detailed output. That's where the clutter goes.
class detailed { // Storing a reference can lead to UB, so you take a risk if you // use this class for anything besides its intended use, i.e., // as a manipulator. myClass const& mc; public: explicit detailed(myClass const& mc) : mc{ mc } {} friend std::ostream& operator<< (std::ostream& ost, detailed const& d) { // Call this function for "detailed" output. // Put all the "clutter" here. You can access all the members // of class `myClass`, both public and private. ost << d.mc.detail << '\n'; return ost; } };
When you want detailed output, invoke the constructor of class detailed with a myClass object as its argument. The constructor creates a temporary, detailed object as a proxy , which is then output by operator<<.
myClass myObject; std::cout << detailed(myObject) << '\n';
Here is the complete program, including a two-line test driver.
// main.cpp #include <iostream> #include <string> class detailed; class myClass { std::string regular{ "Regular: no detail" }; std::string detail{ "Detailed: too much information" }; public: friend std::ostream& operator<< (std::ostream& ost, myClass const& mc) { // Call this function for "regular" output. ost << mc.regular; return ost; } // The friend declaration below is the only modification you need to // make in `myClass`. Friendship give access to the private members, // so you don't need to clutter `myClass` with debugging details used // for "detailed" output. friend std::ostream& operator<< (std::ostream& ost, detailed const& d); }; class detailed { // Storing a reference can lead to UB, so you take a risk if you // use this class for anything besides its intended use, i.e., // as a manipulator. myClass const& mc; public: explicit detailed(myClass const& mc) : mc{ mc } {} friend std::ostream& operator<< (std::ostream& ost, detailed const& d) { // Call this function for "detailed" output. // Put all the "clutter" here. You can access all the members // of class `myClass`, both public and private. ost << d.mc.detail << '\n'; return ost; } }; int main() { myClass myObject; std::cout << myObject << '\n' << detailed(myObject) << '\n'; return 0; } // end file: main.cpp
Output:
Regular: no detail Detailed: too much information
Function info – A simple alternative
In my own projects, I often add member function info to a class when I need debugging information. Function info returns a std::string which contains the state of an object. This is the solution suggested by @dimich in the comments.
These days, I like to use std::format to create the information string, but in the past, I generally used a std::stringstream.
class myClass { std::string regular{ "Regular: no detail" }; std::string detail{ "Detailed: too much information" }; public: auto info(std::string_view heading) const { return std::format( "{}" "\n regular : {}" "\n detail : {}" "\n" , heading, regular, detail ); } // the rest of `myClass`... };
Getting debug information is trivial. Here, I am "debugging" function foo:
void foo(myClass& myObject) { std::cout << myObject.info("myObject, entering function `foo`"); // ... std::cout << myObject.info("myObject, exiting function `foo`"); }
cout << myObject.detailed << "\n";is::operator<<(::operator<<(cout, myObject.detailed), "\n");. It explains where you are wrong.detailedto be a steam manipulator.myClass::detailed()returnstd::string.<< detailed(my_object). But since it's now widely agreed that the wholeostreaminfrastructure is inferior tostd::format, I suggest to learn about writing customstd::formatters instead.