[Qt-interest] Semi-OT: indentation with operator<<
Andre Somers
andre at familiesomers.nl
Mon Aug 2 08:03:19 CEST 2010
Op 2-8-2010 2:14, K. Frank schreef:
> Hello Andre -
>
> Thanks for your refinement.
>
You're welcome.
> On Wed, Jul 28, 2010 at 2:48 PM, Andre Somers<andre at familiesomers.nl> wrote:
>
>> ...
>> If you want, you could wrap it up into a RAII class, so you can not
>> forget about it and early exits and the likes are automatically handled.
>> That might make it slightly cleaner to work with, perhaps.
>>
>> *That* would IMHO be the C++ way to do it.
>>
> I think I follow what you are saying. To make it concrete, let
> me add the static variable you mention and refer back to my
> example:
>
> class Indenter {
> public:
> Indenter() {++indentation_level;}
> ~Indenter() {--indentation_level;}
> static int level() {return indentation_level;}
> static int indentation_level = 0;
> }
>
Something like that, but I would make the indentation_level private, and
level() non static. Also, I think you can not initialize like that.
AFAIK, you need to initialize from an implementation file somewhere. I
would initialize to -1, read on for the why. Also, as a helper funtion,
perhaps you should make the indenter itself streamable, so you get rid
of the for loops everywhere else. That will clean up your code a *lot*:
> class MoreStuff {
> // ...
> friend std::ostream& operator<< (std::ostream& o, MoreStuff const& m);
> };
>
> // Indenter-based implementation
>
> std::ostream& operator<< (std::ostream& o, MoreStuff const& m) {
> for (unsigned i = 0; i< Indenter::level(); i++) o<< ' ';
> o<< "double1_ = "<< m.double1_<< "\n";
> for (unsigned i = 0; i< Indenter::level(); i++) o<< ' ';
> o<< "point3d_ = "<< m.point3d_<< "\n";
> for (unsigned i = 0; i< indent_depth; i++) o<< ' ';
> o<< "someStuff_ = ...\n";
> {<-- braces to define scope of RAII Indenter
> Indenter i;<-- constructor increments indentation_level
> o<< someStuff_;
> }<-- closing brace: destructor decrements indentation_level
> return o;
> }
>
Note quite, I'd say.
If you initialize to -1 and make the indenter streamable, you can
rewrite it to something like this:
// Indenter-based implementation, version 2
std::ostream& operator<< (std::ostream& o, MoreStuff const& m) {
Indenter indent;<-- constructor increments indentation_level. Initial use will yield 0.
o<< indent<< "double1_ = "<< m.double1_<< "\n";
o<< indent<< "point3d_ = "<< m.point3d_<< "\n";
o<< indent<< "someStuff_ = ...\n";
o<< someStuff_;
return o;
// Indenter indent goes out of scope and gets decreased automatically.
}
That is, in *all* your classes that should work with an indent, start with constructing the Indenter instance. Best not to call it i, as i is kind of reserved for loop counters so that may be confusing. In your small piece of code, you already use i like that too!
If you initialize Indenter::indentation_level to -1, the first use will yield you a level 0. Making level() non-static will make sure you don't forget to create an instance before using it. In the class implementation for someStuff_, you do the same, so it will be indented at a higher level. If you ever decide to put MoreStuff itself inside another class or struct that you want to ouput in the same way, you don't need to change anything. Just implement EvenMoreStuff's stream operator in the same way, and your indenter will just work correctly.
If your create a stream implementation for Indenter itself, your code will look much cleaner as you can see above (and there will be less of it, so less chances for mistakes).
> Makes sense to me.
>
I hope the version above makes even more sense to you. :-)
André
More information about the Qt-interest-old
mailing list