Accessing data from a nested class elegantly - c++

I have the following class:
class BigNum
{
public:
BigNum(string StrNumber) : Number(std::move(StrNumber)) {}
BigNum(const char *StrNumber) : Number(string(StrNumber)) {}
~BigNum() = default;
struct
{
string HEX() { return Number + " - HEX"; }
string DEC() { return Number + " - DEC"; }
string BIN() { return Number + " - BIN"; }
}ToString;
private:
string Number;
};
And in the end I wand to elegantly access functions from that structure in the following way:
BigNum a = "1234";
cout << "a = " << a.ToString.DEC() << endl;
cout << "b = " << a.ToString.HEX() << endl;
The problem here is that I cannot access variable Number from my structure.
I know that something like this would solve my problem:
struct
{
string HEX(BigNum &parent) { return parent.Number + " - HEX"; }
...
}ToString;
The problem with this solution is that it is not comfortable to always pass a pointer to my instance.
What would be a solution in this case to have data in nested class and in the same time to keep calls as simple as a.ToString.DEC()?

In some way you have to give ToString a reference or a pointer to the BigNum object so you can access Number. How about something like this:
class BigNum
{
public:
BigNum(string StrNumber) : Number(std::move(StrNumber)) {}
BigNum(const char* StrNumber) : Number(string(StrNumber)) {}
~BigNum() = default;
// you can make the struct private so the type is not visible externally
struct ToStringType
{
private:
const BigNum& ref;
public:
ToStringType(const BigNum& r) : ref(r) {}
string HEX() { return ref.Number + " - HEX"; }
string DEC() { return ref.Number + " - DEC"; }
string BIN() { return ref.Number + " - BIN"; }
};
ToStringType ToString{ *this };
private:
string Number;
};
Irrelevant, but I would recommend to simply have separate ToStringHex, ToStringDec and ToStringBin functions. Saves on not storing a reference, plus the API is easier this way.

I don't see any rationale in the ToString struct.
Just leave the methods in BIGNUM and you are done.
However, for this specific application (changing the rendering style of your given objet in an ostream) I would let your object to be printed with the typical operator<< overaloading, and then modify the rendering style using io-manipulators, so that you will be able to:
cout << "a (DEC) = " << BigNum::DEC << a << endl;
cout << "a (HEX) = " << BigNum::HEX << a << endl;
A full fledged example:
#include <iostream>
#include <iomanip>
using namespace std;
class BigNum
{
public:
BigNum(string StrNumber) : Number(std::move(StrNumber)) {}
BigNum(const char *StrNumber) : Number(string(StrNumber)) {}
~BigNum() = default;
static std::ios_base& DEC(std::ios_base& os) {
os.iword(rendering_style_xalloc) = 0;
return os;
}
static std::ios_base& HEX(std::ios_base& os) {
os.iword(rendering_style_xalloc) = 1;
return os;
}
static std::ios_base& BIN(std::ios_base& os) {
os.iword(rendering_style_xalloc) = 2;
return os;
}
private:
static int rendering_style_xalloc;
string Number;
friend ostream &operator << (ostream &ostr, const BigNum &bignum);
};
int BigNum::rendering_style_xalloc = std::ios_base::xalloc();
ostream &operator << (ostream &os, const BigNum &bignum) {
switch (os.iword(BigNum::rendering_style_xalloc)) {
case 0:
os << bignum.Number << " - DEC";
break;
case 1:
os << bignum.Number << " - HEX";
break;
case 2:
os << bignum.Number << " - BIN";
break;
default:
os << bignum.Number << " - UNK";
break;
}
return os;
}
int main(int argc, char **argv)
{
BigNum a = "1234";
cout << BigNum::DEC << "a (DEC) = " << a << endl;
cout << BigNum::HEX << "a (HEX) = " << a << endl;
}
References:
https://en.cppreference.com/w/cpp/io/ios_base/iword

Related

no operator "<<" matches these operands -- operand types are: std::ostream << Dual [duplicate]

This question already has answers here:
How can I use cout << myclass
(5 answers)
Closed 1 year ago.
I am getting trouble to output the object. I get an error in "cout << sum;" line. How can I print this Dual Number Object as D(float, float).
#include <iostream>
using namespace std;
class Dual{
public:
float val, eps;
Dual(float v, float e){
val = v;
eps = e;
}
Dual operator+(Dual const &obj) {
Dual res(0, 0);
res.val = val + obj.val;
res.eps = eps + obj.eps;
return res;
}
void print() const {
cout << "Dual(" << val << ", " << eps << endl;
}
};
int main(){
Dual d1(1, 2), d2(4, 5);
Dual sum = d1 + d2;
cout << sum;
return 0;
}
Change:
void print() const {
cout << "Dual(" << val << ", " << eps << endl;
}
to something like this:
friend std::ostream &operator<<(std::ostream &os, Dual const &d) {
os << "Dual(" << d.val << ", " << d.eps << ")";
return os;
}
... and off you go. Note that I've intentionally omitted printing a new-line as part of printing the Dual object. Oh, and when you want a new-line, just use "\n", not std::endl, which (at least IMO) was kind of a mistake and should be avoided in general.
You have not defined an operator<< for Dual, that is why you are getting the error. You do, however, have a print() method implemented, but you are not using it.
So, you can either:
simply change cout << sum; to sum.print();
int main(){
Dual d1(1, 2), d2(4, 5);
Dual sum = d1 + d2;
sum.print();
return 0;
}
otherwise, implement operator<<:
class Dual{
public:
float val, eps;
...
};
ostream& operator<<(ostream &os, Dual const &obj) {
os << "Dual(" << obj.val << ", " << obj.eps << endl;
return os;
}
If you still want to use print(), you should change it to take an ostream as input:
class Dual{
public:
float val, eps;
...
void print(ostream &os) const {
os << "Dual(" << val << ", " << eps << endl;
}
};
ostream& operator<<(ostream &os, Dual const &obj)
{
obj.print(os);
return os;
}
Then, you can use either of these:
cout << sum;
sum.print(cout);

How to add a custom prefix in a << operator for a custom object

Is there a way to add a custom prefix in the operator<< for an object that I implement?
Ex:
class A {
public:
std::string id;
int count;
};
std::ostream &operator<<(std::ostream &os, const A &a)
{
os << os.prefix() << "Id: " << a.id << "\n";
os << os.prefix() << "Count: " << a.count << "\n";
return os;
}
If I do something like this:
A a;
a.id = "foo";
a.count = 1;
std::cout << a << std::endl;
The output will be:
Id: foo
Count: 1
I want to do something like:
std::cout << set_prefix(" -") << a << std::endl;
std::cout << set_prefix("==>") << a << std::endl;
To get an output like this:
-Id: foo
-Count: 1
==>Id: foo
==>Count: 1
A suggestion is to use std::setfill and os.fill, but std::setfill takes a single char as an argument and I need a custom string instead.
Solution
Looking at operator<<(std::basic_ostream) documentation, I found this:
Before insertion, first, all characters are widened using
os.widen(), then padding is determined as follows: if the number of
characters to insert is less than os.width(), then enough copies of
os.fill() are added to the character sequence to make its length
equal os.width(). If (out.flags()&std::ios_base::adjustfield) ==
std::ios_base::left, the fill characters are added at the end of the
output sequence, otherwise they are added before the output sequence.
After insertion, width(0) is called to cancel the effects of
std::setw, if any.
So the solution that works for me was save the original width of stream at the beggining and than recovering them when necessary.
std::ostream &operator<<(std::ostream &os, const A &a)
{
auto w = os.width();
os << std::setw(w) << "" << "Id: " << a.id << "\n";
os << std::setw(w) << "" << "Count: " << a.count;
return os;
}
Then:
std::cout << a << std::endl;
std::cout << std::setw(4) << a << std::endl;
std::cout << std::setfill('>') << std::setw(2) << a << std::endl;
Gave the following output:
Id: foo
Count: 1
Id: foo
Count: 1
>>Id: foo
>>Count: 1
Maybe a bit of overkill, but you can use something like this:
#include <iostream>
#include <sstream>
struct line_buffered_stream {
std::ostream& out;
std::stringstream ss;
std::string prefix;
line_buffered_stream(std::ostream& out,std::string prefix) :
out(out),prefix(prefix) {}
template <typename T>
auto operator<<(const T& t) -> decltype(this->ss << t,*this) {
ss << t;
return *this;
}
~line_buffered_stream(){
std::string line;
while (std::getline(ss,line)){
out << prefix << line << "\n";
}
}
};
int main() {
line_buffered_stream(std::cout,"==>") << "a\nb\n";
line_buffered_stream(std::cout,"-->") << "a\nb\n";
}
output:
==>a
==>b
-->a
-->b
Live Demo
Note that the implementation above is not meant to be used as anything else than a temporary whose lifetime is restricted to a single line of code. If you dont like that you'd have to add some mechanism to flush the stream to std::cout not to wait till the destructor is called.
I do not know of any way to do this with a string, but if you are content with just a char, it looks like you can use std::setfill manipulator, and than in your overload use the fill character:
std::cout << std::setfill('-') << a << std::endl;
std::ostream &operator<<(std::ostream &os, const A &a)
{
os << os.fill() << "Id: " << a.id << "\n";
os << os.fill() << "Count: " << a.count << "\n";
return os;
}
I'm not a big fan of this because it uses a global variable but that does allow you to have other classes use this same method, they just have to write thier own operator << correctly. It also requires that you call set_prefix(""); when you want to clear the prefix from printing. That said it does allow you to prepend any string you want to the output.
namespace details
{
// we neeed this for tag dispatch
struct Prefix {};
// this will be used in the class(es) operator << for the line prefix
std::string prefix;
// allows set_prefix to be called in the output stream by eating it return and returning the stream as is
std::ostream& operator <<(std::ostream& os, const Prefix& prefix)
{
return os;
}
}
// set the prefix and return a type that allows this to be placed in the output stream
details::Prefix set_prefix(const std::string& prefix)
{
details::prefix = prefix;
return {};
}
class A {
public:
std::string id;
int count;
};
std::ostream &operator<<(std::ostream &os, const A &a)
{
os << details::prefix << "Id: " << a.id << "\n";
os << details::prefix << "Count: " << a.count << "\n";
return os;
}
int main()
{
A a;
a.id = "foo";
a.count = 1;
std::cout << a << std::endl;
std::cout << set_prefix(" -") << a << std::endl;
std::cout << set_prefix("==>") << a << std::endl;
}
Output:
Id: foo
Count: 1
-Id: foo
-Count: 1
==>Id: foo
==>Count: 1
There is a way to store custom data on a stream object, but it isn't pretty: the iword and pword interfaces.
stream_prefix.hpp:
#ifndef STREAM_PREFIX_HPP_
#define STREAM_PREFIX_HPP_
#include <utility>
#include <string>
#include <ostream>
namespace stream_prefix_details {
class set_prefix_helper {
public:
explicit set_prefix_helper(std::string prefix)
: m_prefix(std::move(prefix)) {}
private:
std::string m_prefix;
// These insertion operators can be found by Argument-Dependent Lookup.
friend std::ostream& operator<<(
std::ostream&, set_prefix_helper&&);
friend std::ostream& operator<<(
std::ostream&, const set_prefix_helper&);
};
}
// The set_prefix manipulator. Can be used as (os << set_prefix(str)).
inline auto set_prefix(std::string prefix)
-> stream_prefix_details::set_prefix_helper
{ return stream_prefix_details::set_prefix_helper{ std::move(prefix) }; }
// Get the prefix previously stored by (os << set_prefix(str)), or
// an empty string if none was set.
const std::string& get_prefix(std::ostream&);
#endif
stream_prefix.cpp:
#include <stream_prefix.hpp>
namespace stream_prefix_details {
int pword_index() {
static const int index = std::ios_base::xalloc();
return index;
}
void stream_callback(std::ios_base::event evt_type,
std::ios_base& ios, int)
{
if (evt_type == std::ios_base::erase_event) {
// The stream is being destroyed, or is about to copy data
// from another stream. Destroy the prefix, if it has one.
void*& pword_ptr = ios.pword(pword_index());
if (pword_ptr) {
delete static_cast<std::string*>(pword_ptr);
pword_ptr = nullptr;
}
} else if (evt_type == std::ios_base::copyfmt_event) {
// The stream just copied data from another stream.
// Make sure we don't have two streams owning the same
// prefix string.
void*& pword_ptr = ios.pword(pword_index());
if (pword_ptr)
pword_ptr =
new std::string(*static_cast<std::string*>(pword_ptr));
}
// Can ignore imbue_event events.
}
std::ostream& operator<<(std::ostream& os,
set_prefix_helper&& prefix_helper)
{
void*& pword_ptr = os.pword(pword_index());
if (pword_ptr)
*static_cast<std::string*>(pword_ptr) =
std::move(prefix_helper.m_prefix);
else {
os.register_callback(stream_callback, 0);
pword_ptr = new std::string(std::move(prefix_helper.m_prefix));
}
return os;
}
std::ostream& operator<<(std::ostream& os,
const set_prefix_helper& prefix_helper)
{
void*& pword_ptr = os.pword(pword_index());
if (pword_ptr)
*static_cast<std::string*>(pword_ptr) = prefix_helper.m_prefix;
else {
os.register_callback(stream_callback, 0);
pword_ptr = new std::string(prefix_helper.m_prefix);
}
return os;
}
}
const std::string& get_prefix(std::ostream& os)
{
void* pword_ptr = os.pword(stream_prefix_details::pword_index());
if (pword_ptr)
return *static_cast<std::string*>(pword_ptr);
else {
// This string will never be destroyed, but it's just one object.
// This avoids the Static Destruction Order Fiasco.
static const std::string* const empty_str = new const std::string;
return *empty_str;
}
}
Usage:
#include <iostream>
#include <stream_prefix.hpp>
class A {
public:
std::string id;
int count;
};
std::ostream &operator<<(std::ostream &os, const A &a)
{
os << get_prefix(os) << "Id: " << a.id << "\n";
os << get_prefix(os) << "Count: " << a.count << "\n";
return os;
}
int main() {
A a;
a.id = "foo";
a.count = 1;
std::cout << a << std::endl;
std::cout << set_prefix("==> ") << a << std::endl;
}
Full working demo here.
Note this set_prefix manipulator is "sticky", meaning the setting will remain on the stream after use, like most of the standard manipulators except for std::setw. If you want it to reset after you're done outputting an A object description, just add os << set_prefix(std::string{}); to the operator<< function.
This works, but it is very, very ugly and terrible code.
Couple of issues:
- operator<< has to be defined outside of the class, because you want to take in class A as the rhs argument, instead of invoking it like A::operator<<() - and actually taking in a second A class as an argument.
- cout cannot deal with a void output, so because you insist on chaining setting the prefix with the cout commant, it has to return an empty string object.
- If you don't want the prefix to be remembered, just do prefix.clear() at the end of the operator<< definition.
class A
{
public:
std::string id;
std::string prefix;
int count;
std::string set_prefix(const std::string& inp)
{
prefix = inp;
return std::string();
}
std::string get_prefix() const
{
return prefix;
}
};
std::ostream &operator<<(std::ostream &os, const A &input)
{
os << input.get_prefix() << "Id: " << input.id << "\n";
os << input.get_prefix() << "Count: " << input.count << "\n";
return os;
}
int main()
{
A class1;
class1.id = "test";
class1.count = 5;
std::cout << class1.set_prefix(" -") << class1; // endl removed, as your operator<< definition already has a "\n" at the end.
std::cout << class1.set_prefix("==>") << class1;
}

Overloading operator <<

class Vehicle
{
public:
//[...]
virtual std::ostream& ostreamOutput(std::ostream&) const; // virtual in order to use it for subclasse like cars, busses etc.
virtual double Speed() const; //returns the speed of a vehicle, is implemented in derived classes
private:
int Number
std::string Name
//[...]
protected:
int MaxSpeed; //these variables were also needed in the derived classes
};
std::ostream& Vehicle::ostreamOutput(std::ostream& os) const
{
os << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::left) << std::setfill(' ') << ""
<< std::setw(4) << Number
<< std::setw(9) << Name
<< std::setw(15) << Speed()
<< std::setw(5) << MaxSpeed
return os;
}
std::ostream& operator<<(std::ostream& os, const Vehicle& x)
{
x.ostreamOutput(os);
return os;
}
main() //I wanted to overload the "<<"-Operator in order to print the vehicle information without //a seperate function
{
Vehicle Vehicle1("Vehicle1", 80);
std::cout << Vehicle1 << std::endl;//the first shift-operator contains the error
}
I tried to overload the Shiftoperator but I get the error named:
"error c2679 binary ' ' no operator found which takes a right-hand operand of type".
The error occured in the first Shift Operator in the main function. I want to print Vehicle and its derived classes with the overloaded operator.
Can you explain the error to me? I really do not know how to correct this.
I fixed all the typos (missed semicolons) in your source, and here is a complete working example:
#include <iostream>
#include <iomanip>
using namespace std;
class Vehicle
{
public:
//[...]
Vehicle (const char* Name, int Number)
: Name (Name), Number (Number)
{}
virtual std::ostream& ostreamOutput(std::ostream&) const; // virtual in order to use it for subclasse like cars, busses etc.
virtual double Speed() const {return 0.;} //returns the speed of a vehicle, is implemented in derived classes
private:
// remove in-class initializers below if you need to avoid C++11
int Number = -1;
std::string Name = "not set";
//[...]
protected:
int MaxSpeed = 200; //these variables were also needed in the derived classes
};
std::ostream& Vehicle::ostreamOutput(std::ostream& os) const
{
os << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::left) << std::setfill(' ') << ""
<< std::setw(4) << Number
<< std::setw(9) << Name
<< std::setw(15) << Speed()
<< std::setw(5) << MaxSpeed;
return os;
}
std::ostream& operator<<(std::ostream& os, const Vehicle& x)
{
x.ostreamOutput(os);
return os;
}
int main() //I wanted to overload the "<<"-Operator in order to print the vehicle information without //a seperate function
{
Vehicle Vehicle1("Vehicle1", 80);
std::cout << Vehicle1 << std::endl;//the first shift-operator contains the error
}
Maybe you output some other variables for which operator<< is not defined. To debug this case, split the code from e.g. this:
os << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::left) << std::setfill(' ') << ""
<< std::setw(4) << Number
<< std::setw(9) << Name
<< std::setw(15) << Speed()
<< std::setw(5) << MaxSpeed;
to this:
os << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::left) << std::setfill(' ') << ""
<< std::setw(4) << Number;
os << std::setw(9) << Name;
os << std::setw(15) << Speed();
os << std::setw(5) << MaxSpeed;
This way you'll get the error message for the real line that is causing trouble. Otherwise you'll get the error message only for the first line, the compiler you use apparently does not distinguish the lines in this case.
Your code example contains only typos (Vehicle <-> Fahrzeug, ostreamAusgabe <-> ostreamOutput, semicolon after Speed() in ostreamOutput()). Overloaded operator<< should work fine.
Try to compile and launch this code:
class Vehicle
{
public:
Vehicle(const std::string& name, int num)
: Name(Name)
, Number(num)
, MaxSpeed(100)
{}
virtual std::ostream& ostreamOutput(std::ostream&) const;
virtual double Speed() const;
private:
int Number;
std::string Name;
protected:
int MaxSpeed;
};
double Vehicle::Speed() const
{
return 0.0;
}
std::ostream& Vehicle::ostreamOutput(std::ostream& os) const
{
os << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::left) << std::setfill(' ') << ""
<< std::setw(4) << Number
<< std::setw(9) << Name
<< std::setw(15) << Speed()
<< std::setw(5) << MaxSpeed;
return os;
}
std::ostream& operator<<(std::ostream& os, const Vehicle& x)
{
x.ostreamOutput(os);
return os;
}
int main()
{
Vehicle Vehicle1("Vehicle1", 80);
std::cout << Vehicle1 << std::endl;
return 0;
}

Access Elements of Vector - C++

I have the following class:
class Friend
{
public:
Friend();
~Friend(){}
void setName(string friendName){ name = friendName; }
void setAge(int friendAge) { age = friendAge; }
void setHeight(int friendHeight) { height = friendHeight; }
void printFriendInfo();
private:
string name;
int age;
float height;
};
//implementations
Friend::Friend()
{
age = 0;
height = 0.0;
}
//printing
void Friend::printFriendInfo()
{
cout << "Name : " << name << endl;
cout << "Age : " << age << endl;
cout << "Height : " << height << endl << endl;
}
And At this moment I can introduce the values in a vector, like this:
std::vector<Friend> regist(4, Friend());
regist[1].setAge(15);
regist[1].setHeight(90);
regist[1].setName("eieiei");
regist[2].setAge(40);
regist[2].setHeight(85);
regist[2].setName("random");
In debug, this solution works fine. But now I am trying to print the vector. So far without success.
for (int i = 0; i < regist.size(); i++) {
cout << regist[i]; //<-- error here
cout << '\n';
}
You might redesign a bit (in essence):
#include <iostream>
class Friend
{
public:
Friend();
// A more general name, const, and taking a stream.
void write(std::ostream&) const;
private:
std::string name;
int age;
float height;
};
Friend::Friend()
{
age = 0;
height = 0.0;
}
void Friend::write(std::ostream& stream) const
{
stream << "Name : " << name << std::endl;
stream << "Age : " << age << std::endl;
stream << "Height : " << height << std::endl << std::endl;
}
// Forward to the member function
inline std::ostream& operator << (std::ostream& stream, const Friend& object) {
object.write(stream);
return stream;
}
int main() {
Friend f;
std::cout << f;
}
Just call the printFriendInfo() member function:
for (int i = 0; i < regist.size(); i++) {
regist[i].printFriendInfo();
}
For
cout << regist[i];
to work, add a few accessor functions in Friend
string getName() const { return name; }
int getAge() const { return age; }
float getHeight() const { return height; }
and implement an overloaded operator<< function:
std::ostream& operator<<(std::ostream& out, Friend const& f)
{
out << "Name : " << f.getName() << std::endl;
out << "Age : " << f.getAge() << std::endl;
out << "Height : " << f.getHeight() << std::endl;
return out;
}

Writing a manipulator for a custom stream class

I've written a custom stream class that outputs indented text and that has manipulators that can change the indent level. All of the indenting work is implemented in a custom stream buffer class, which is used by the stream class. The buffer is working (i.e. text is indented in the output), but I can't get my manipulators to work. I was reading in a lot of places how ostream (which my class extends) overloads the operator<< like this:
ostream& ostream::operator << ( ostream& (*op)(ostream&))
{
// call the function passed as parameter with this stream as the argument
return (*op)(*this);
}
Which means it can take in a function as a parameter. So why aren't my "indent" or "deindent" stream functions being recognized? I'm sure I have to do some overloading of operator<<, but shouldn't I not need to? See below for my code:
#include <iostream>
#include <streambuf>
#include <locale>
#include <cstdio>
using namespace std;
class indentbuf: public streambuf {
public:
indentbuf(streambuf* sbuf): m_sbuf(sbuf), m_indent(4), m_need(true) {}
int indent() const { return m_indent; }
void indent() { m_indent+=4; }
void deindent() { if(m_indent >= 4) m_indent-= 4; }
protected:
virtual int_type overflow(int_type c) {
if (traits_type::eq_int_type(c, traits_type::eof()))
return m_sbuf->sputc(c);
if (m_need)
{
fill_n(ostreambuf_iterator<char>(m_sbuf), m_indent, ' ');
m_need = false;
}
if (traits_type::eq_int_type(m_sbuf->sputc(c), traits_type::eof()))
return traits_type::eof();
if (traits_type::eq_int_type(c, traits_type::to_char_type('\n')))
m_need = true;
return traits_type::not_eof(c);
}
streambuf* m_sbuf;
int m_indent;
bool m_need;
};
class IndentStream : public ostream {
public:
IndentStream(ostream &os) : ib(os.rdbuf()), ostream(&ib){};
ostream& indent(ostream& stream) {
ib.indent();
return stream;
}
ostream& deindent(ostream& stream) {
ib.deindent();
return stream;
}
private:
indentbuf ib;
};
int main()
{
IndentStream is(cout);
is << "31 hexadecimal: " << hex << 31 << endl;
is << "31 hexadecimal: " << hex << 31 << endl;
is << "31 hexadecimal: " << hex << 31 << deindent << endl;
return 0;
}
Thanks!
Your manipulator should be declared as a function which accepts just one argument of type ostream&. However, if you make it a member function, you know there is an implicit this argument being passed to the function as well.
Thus, you should rather declare your manipulator as a free, non-member function, making it friend of your class so that it can access its private member ib:
class IndentStream : public ostream {
public:
IndentStream(ostream &os) : ib(os.rdbuf()), ostream(&ib){};
ostream& indent(ostream& stream) {
ib.indent();
return stream;
}
friend ostream& deindent(ostream& stream);
// ^^^^^^
private:
indentbuf ib;
};
ostream& deindent(ostream& stream)
{
IndentStream* pIndentStream = dynamic_cast<IndentStream*>(&stream);
if (pIndentStream != nullptr)
{
pIndentStream->ib.deindent();
}
return stream;
}
int main()
{
IndentStream is(cout);
is << "31 hexadecimal: " << hex << 31 << endl;
is << "31 hexadecimal: " << hex << 31 << deindent << endl;
is << "31 hexadecimal: " << hex << 31 << endl;
return 0;
}
Alternatively, if you really want your function to be a member, you could make it static:
class IndentStream : public ostream {
public:
IndentStream(ostream &os) : ib(os.rdbuf()), ostream(&ib){};
ostream& indent(ostream& stream) {
ib.indent();
return stream;
}
static ostream& deindent(ostream& stream)
{
IndentStream* pIndentStream = dynamic_cast<IndentStream*>(&stream);
if (pIndentStream != nullptr)
{
pIndentStream->ib.deindent();
}
return stream;
}
private:
indentbuf ib;
};
However, this would force you to use a qualified name to refer to it:
int main()
{
IndentStream is(cout);
is << "31 hexadecimal: " << hex << 31 << endl;
is << "31 hexadecimal: " << hex << 31 << IndentStream::deindent << endl;
// ^^^^^^^^^^^^^^
is << "31 hexadecimal: " << hex << 31 << endl;
return 0;
}