6

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???

Michael
  • 706
  • 9
  • 29
  • Hint: Take a look at the overloads of `operator<<` for `std::ostream`s: http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt – dyp Dec 30 '13 at 15:42
  • 1
    Hint2: An `ios_base` has no `operator>>` nor `operator<<` defined. That's why `toggle(cout) << "something"` doesn't work. – dyp Dec 30 '13 at 15:44
  • 1
    +1 This is a refreshing example of how to ask a homework question. – Roger Rowland Dec 30 '13 at 15:44
  • Hint 3 (spoiler alert ;) Take a look at [how `endl` is defined](http://en.cppreference.com/w/cpp/io/manip/endl) – dyp Dec 30 '13 at 15:47
  • @ DyP: Sorry, but your spoiler alert hint does not help me much :-( The point is, that I really should define the function as `ios_base& my_manip(basic_ios&)` (even though I do not get what it could be useful for...) – Michael Dec 30 '13 at 16:08
  • 1
    @Michael The point is that `std::ostream` has several `operator<<` overloads that take function pointers and calls them. Using manipulators like `std::endl`, `std::hex` or your own is typically done by calling the `operator<<` (or `operator>>` for `istream`s) of the stream and passing a *pointer to the manipulator function*. Note that function names decay to pointers to those functions. – dyp Dec 30 '13 at 16:33
  • by the way: is there a difference between std::basic_ostream and std::ostream? If not, why are there two names? – Michael Dec 30 '13 at 16:41
  • 1
    @Michael `std::ostream` is a typedef for `std::basic_ostream`. There's also `std::wostream`, a typedef for `std::basic_ostream`. – dyp Dec 30 '13 at 16:44
  • 1
    *"What I still do NOT understand, is the motivation to pass a `basic_ios` and give back `ios_base`"* Nobody spotted that yet :D -- It's an error if the manipulator is intended to be used as `stream<& my_manip(basic_ios&)` or `ios_base& my_manip(ios_base&)`. In your case, I think the base class `ios_base` is sufficient, it already provides the necessary functionality and is therefore the more general choice (see [this class diagram](http://en.cppreference.com/w/cpp/io)). When using `ios_base`, you don't need a function template. – dyp Jan 02 '14 at 12:28

2 Answers2

4

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';
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
2

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.

James Kanze
  • 150,581
  • 18
  • 184
  • 329