Reputation: 1500
So I want to write an indent output class that can be used like this:
Debug f;
f.open("test.txt");
f << Debug::IndS << "Start" << std::endl;
f << Debug::Ind << "test" << std::endl;
f << Debug::IndE << "End" << std::endl;
which would output:
Start
test
End
So IndS would print out current indent and increment indent, Ind would print out the current indent and IndE would decrement indent and print out the current indent. I have tried to create it like so:
class Debug : public std::ofstream {
public:
Debug();
~Debug();
private:
std::string IndentText;
int _Indent;
public:
void SetIndentText(const char* Text);
inline void Indent(int Amount);
inline void SetIndent(int Amount);
inline std::ofstream& Ind (std::ofstream& ofs);
inline std::ofstream& IndS(std::ofstream& ofs);
inline std::ofstream& IndE(std::ofstream& ofs);
};
Debug::Debug () : std::ofstream() {
IndentText = " ";
}
Debug::~Debug () {
}
void Debug::SetIndentText (const char* Text) {
IndentText = Text;
}
void Debug::Indent (int Amount) {
_Indent += Amount;
}
void Debug::SetIndent(int Amount) {
_Indent = Amount;
}
std::ofstream& Debug::Ind (std::ofstream& ofs) {
for (int i = 0;i < _Indent;i++) {
ofs << IndentText;
}
return ofs;
}
std::ofstream& Debug::IndS (std::ofstream& ofs) {
ofs << Ind;
_Indent++;
return ofs;
}
std::ofstream& Debug::IndE (std::ofstream& ofs) {
_Indent--;
ofs << Ind;
return ofs;
}
So I think there are a few problems with this:
It does not compile. Errors with no match for 'operator<<' (operand types are 'std::ofstream {aka std::basic_ofstream<char>}' and '<unresolved overloaded function type>') ofs << Ind; candidates are:
blah blah
I don't override all constructors. Is there a way to do this? I think I just have to rewrite all the constructors to do IndentText = " ";
and delegate the overloaded constructor
Could someone help me with this? Thanks!
Upvotes: 1
Views: 2246
Reputation: 1
You usually shouldn't inherit std::ostream
or implementations of it like std::ofstream
. Wrap them into another class instead.
Here's a short sketch of my ideas mentioned in the comments
#include <iostream>
#include <fstream>
using namespace std;
class Logger {
public:
Logger(ostream& os) : os_(os), curIndentLevel_(0) {}
void increaseLevel() { ++curIndentLevel_; }
void decreaseLevel() { --curIndentLevel_; }
private:
template<typename T> friend ostream& operator<<(Logger&, T);
ostream& os_;
int curIndentLevel_;
};
template<typename T>
ostream& operator<<(Logger& log, T op) {
for(int i = 0; i < log.curIndentLevel_ * 4; ++i) {
log.os_ << ' ';
}
log.os_ << op;
return log.os_;
}
int main() {
Logger log(cout);
log.increaseLevel();
log << "Hello World!" << endl;
log.decreaseLevel();
log << "Hello World!" << endl;
return 0;
}
Output
Hello World!
Hello World!
Here's a little variant, showing how you can shortcut the coding with operator<<()
overloads:
class Logger {
public:
Logger(ostream& os) : os_(os), curIndentLevel_(0) {}
Logger& increaseLevel() { ++curIndentLevel_; return *this; }
Logger& decreaseLevel() { --curIndentLevel_; return *this; }
// ... as before ...
};
int main() {
Logger log(cout);
log.increaseLevel() << "Hello World!" << endl;
log.decreaseLevel() << "Hello World!" << endl;
return 0;
}
The same way you can go to provide additional I/O manipulator style free functions.
Upvotes: 3
Reputation: 1500
Alternative solution:
#include <iostream>
#include <fstream>
class IndentClass {
public:
IndentClass();
~IndentClass();
private:
std::string IndentText;
int _Indent;
public:
inline void SetIndentText(const char* Text);
inline void Indent(int Amount);
inline void SetIndent(int Amount);
inline void ind (std::ostream& ofs);
class Ind_t {
public:
IndentClass& state;
Ind_t (IndentClass& _state) : state(_state) {}
friend inline std::ostream& operator<< (std::ostream& ofs, Ind_t& ind);
};
class IndS_t {
public:
IndentClass& state;
IndS_t (IndentClass& _state) : state(_state) {}
friend inline std::ostream& operator<< (std::ostream& ofs, IndS_t& ind);
};
class IndE_t {
public:
IndentClass& state;
IndE_t (IndentClass& _state) : state(_state) {}
friend inline std::ostream& operator<< (std::ostream& ofs, IndE_t& ind);
};
Ind_t Ind;
IndS_t IndS;
IndE_t IndE;
};
IndentClass::IndentClass () : IndentText(" "), _Indent(0), Ind(*this), IndS(*this), IndE(*this) {
}
IndentClass::~IndentClass () {
}
void IndentClass::SetIndentText (const char* Text) {
IndentText = Text;
}
void IndentClass::Indent (int Amount) {
_Indent += Amount;
}
void IndentClass::SetIndent(int Amount) {
_Indent = Amount;
}
void IndentClass::ind (std::ostream& ofs) {
for (int i = 0;i < _Indent;i++) {
ofs << IndentText;
}
}
std::ostream& operator<< (std::ostream& ofs, IndentClass::Ind_t& ind) {
ind.state.ind(ofs);
return ofs;
}
std::ostream& operator<< (std::ostream& ofs, IndentClass::IndS_t& inds) {
inds.state.ind(ofs);
inds.state.Indent(1);
return ofs;
}
std::ostream& operator<< (std::ostream& ofs, IndentClass::IndE_t& inde) {
inde.state.Indent(-1);
inde.state.ind(ofs);
return ofs;
}
int main () {
IndentClass i;
std::cout << i.IndS << "test" << std::endl;
std::cout << i.Ind << "test" << std::endl;
std::cout << i.IndE << "test" << std::endl;
return 0;
}
Upvotes: 2