Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use this manipulator

This is a exercise for school, so please provide just hints and no complete examples ;-)

I have my own manipulator:

template<typename T, typename Tr=char_traits<T> >
ios_base& toggle(basic_ios<T,Tr>& io)
{
    if(io.flags() & ios::scientific)
    { io.unsetf(ios::scientific); io.flags(ios::fixed); }
    else { io.unsetf(ios::fixed); io.flags(ios::scientific); }
    return io;
 }

I wrote this, because I have to write a manipulator with the form ios_base& my_manip(basic_ios&).

If I use it like this (without using return value):

toggle(cout);

... that works fine. But if I use it like that:

toggle(cout) << 54444.6456555 << endl;

That does not work (Because std::ios_base does not have operator<<() as stated below).

In general I do not get what ios_base& my_manip(basic_ios&) could be useful for... Do you have a hint/example?


You guys already helped me a lot! What I still do NOT understand, is the motivation to pass a basic_ios and give back ios_base (because that is suggested to do in the exercise I have to solve...). What could be a possible scenario to use this???

like image 530
Michael Avatar asked Dec 30 '13 15:12

Michael


2 Answers

The problem with the manipulator is that it returns an std::ios_base& rather than a std::ostream& you can write to. You could change the manipulator to take an std::ostream& as parameter and return the reference received. However, the output stream class defines output operators which take pointers to functions:

std::ostream& std::ostream::operator<< (std::ios_base& (*)(std::ios_base&)) { ... }

That is, you can just insert manipulators pretty much the way you would do it with, e.g., std::hex:

std::cout << std::hex << 123 << ' ' << std::dec << 123 << '\n';
like image 105
Dietmar Kühl Avatar answered Nov 17 '22 19:11

Dietmar Kühl


In addition to the issue which Dietmar addressed: io.flags() & ios::scientific does not return a bool, and the conversion to bool probably doesn't do what you want. You need something along the lines of:

if ( (io.flags() & ios::floatfield) == ios::fixed ) {
    io.setf( ios::scientific, ios::floatfield );
} else if ( (io.flags() & ios::floatfield) == ios::scientific ) {
    io.setf( ios::fixed, ios::floatfield );
} else {
    //  Whatever you want to happen first time around...
}

Despite being part of a variable with a type named ...flags, floatfield is not a flag, but a field which can take on at least three values: fixed, scientific and its default value in which neither of these are set. (basefield and adjustfield behave similarly.)

Note too the use of the two argument form of ios::setf; it is designed especially for these bitfield format parameters, and resets the bits in its second argument before setting the ones in its first.

I might add that you probably do not want to call io.flags in your manipulator; this sets all of the formatting flags to the value you give, effectively resetting all other formatting flags. If you're only outputting floating point, this may not be a problem (although showpos, showpoint, uppercase and possibly unitbuf might be relevant), but you never know.

like image 30
James Kanze Avatar answered Nov 17 '22 19:11

James Kanze