Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #7506 > unrolled thread

iostream manipulator construction and design

Started byRuben Safir <ruben@mrbrklyn.com>
First post2011-07-06 02:55 +0000
Last post2011-07-07 11:13 +0200
Articles 7 — 3 participants

Back to article view | Back to comp.lang.c++


Contents

  iostream manipulator construction and design Ruben Safir <ruben@mrbrklyn.com> - 2011-07-06 02:55 +0000
    Re: iostream manipulator construction and design Michael DOUBEZ <michael.doubez@free.fr> - 2011-07-06 01:00 -0700
    Re: iostream manipulator construction and design Ruben Safir <ruben@mrbrklyn.com> - 2011-07-06 15:01 +0000
      Re: iostream manipulator construction and design "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> - 2011-07-06 19:13 +0200
        Re: iostream manipulator construction and design Ruben Safir <ruben@mrbrklyn.com> - 2011-07-06 18:00 +0000
        Re: iostream manipulator construction and design Ruben Safir <ruben@mrbrklyn.com> - 2011-07-07 02:51 +0000
          Re: iostream manipulator construction and design "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> - 2011-07-07 11:13 +0200

#7506 — iostream manipulator construction and design

FromRuben Safir <ruben@mrbrklyn.com>
Date2011-07-06 02:55 +0000
Subjectiostream manipulator construction and design
Message-ID<iv0iqd$alg$1@reader1.panix.com>
I've covered the iostream operations in Stroustrup but there is a section
that I'm failing to understand in section 21.4.6.1 (of the third edition
of C++ - The Programming Language) which I hope that someone can help
me decipher.  The section discusses Manipultors that take arguments and
Stroustrup states

<QUOTE>
"Manipulators that take arguments can also be useful.  For example, we
might want to write

   cout << setprecision(4) << angle;

to print the value of the floating-point variable angle with four
digits.

To do this, setprecision must return an object that is initialized by 4
and that calls cout::setprcision when involked.  Such a manipulator is a
function object thatr is involed by << rather than by ().  The exact
tyoe of function object is implementation-defined, but it might be
defined like this:

   struct smanip{
      ios_base& (*f)(ios_base&, int); //function to be called
      int i;

      smanip(ios_base& (*ff) (ios_base&, int), int ii) : f(ff, i(ii){}
   };

   template<class Ch, class Tr>
   ostream<Ch, Tr>& operator<<(ostream<Ch, Tr>& os, smanip& m)
   {
      return m.f(os, m.i);
   }

The smanip constructor stores its arguments in f and i and the
operator<< calls f(i).  We can now define setprecision() like this:

   ios_base& set_precision(ios)base& s, int n)  //helper
   {
      return s.setprecision(n); //call member function
   }

   inline smap setprecision(int n)
   {
	 return smanip(set_precision, n);
   }

We can now write:
   cout << setprecision(4) << angle;
"   
</QUOTE>

What don't understand a couple of things here, and this might be an
accumulation of increasing confusion on my part as I've continued
through this chapter.

First, I just don't understand what the problem is that is being solved.
Why can't a manipulator just take an argument of an int and return a
base_stream object, like the manipulators that don't take an argument?

Secondly, the exqmple completely befuddles me.  I'm guessing that don't
understand the order of operations of 

   cout << setprecision(4) << angle;

   is ostream<< called first and then the function setprecision?

[toc] | [next] | [standalone]


#7514

FromMichael DOUBEZ <michael.doubez@free.fr>
Date2011-07-06 01:00 -0700
Message-ID<37a44930-d9e1-4c9b-b06d-fc0204ae23a7@j28g2000vbp.googlegroups.com>
In reply to#7506
On Jul 6, 4:55 am, Ruben Safir <ru...@mrbrklyn.com> wrote:
> I've covered the iostream operations in Stroustrup but there is a section
> that I'm failing to understand in section 21.4.6.1 (of the third edition
> of C++ - The Programming Language) which I hope that someone can help
> me decipher.  The section discusses Manipultors that take arguments and
> Stroustrup states
>
> <QUOTE>
> "Manipulators that take arguments can also be useful.  For example, we
> might want to write
>
>    cout << setprecision(4) << angle;
>
> to print the value of the floating-point variable angle with four
> digits.
>
> To do this, setprecision must return an object that is initialized by 4
> and that calls cout::setprcision when involked.  Such a manipulator is a
> function object thatr is involed by << rather than by ().  The exact
> tyoe of function object is implementation-defined, but it might be
> defined like this:
>
>    struct smanip{
>       ios_base& (*f)(ios_base&, int); //function to be called
>       int i;
>
>       smanip(ios_base& (*ff) (ios_base&, int), int ii) : f(ff, i(ii){}
>    };
>
>    template<class Ch, class Tr>
>    ostream<Ch, Tr>& operator<<(ostream<Ch, Tr>& os, smanip& m)
>    {
>       return m.f(os, m.i);
>    }
>
> The smanip constructor stores its arguments in f and i and the
> operator<< calls f(i).  We can now define setprecision() like this:
>
>    ios_base& set_precision(ios)base& s, int n)  //helper
>    {
>       return s.setprecision(n); //call member function
>    }
>
>    inline smap setprecision(int n)
>    {
>          return smanip(set_precision, n);
>    }
>
> We can now write:
>    cout << setprecision(4) << angle;
> "  
> </QUOTE>
>
> What don't understand a couple of things here, and this might be an
> accumulation of increasing confusion on my part as I've continued
> through this chapter.
>
> First, I just don't understand what the problem is that is being solved.

The problem being solved is being able to use a parametrized modifier
with the same syntax.
By example, if you want to uppercase your output, you write:
out<<std::uppercase<<"hello";

This works because ostream (in fact basic_ostream<>) defines an
overload like

basic_ostream<>& operator<<(ios_base& (*pf)(ios_base&))
{
  *pt(*this);
  return *this;
}

And std::uppercase simply set the relevant flag
ios_base& std::uppercase(ios_base& os)
{
  os.setf(ios_base::uppercase);
  return os;
}


> Why can't a manipulator just take an argument of an int and return a
> base_stream object, like the manipulators that don't take an argument?

But now, if you want a parameter to uppercase:
ios_base& set_uppercase(ios_base& os, int isUppercase)
{
  if(isUppercase)os.setf(ios_base::uppercase);
  else           os.unsetf(ios_base::uppercase);
  return os;
}

You cannot directly use set_uppercase because, there is no matching
overload in ostream. C++ provides a magic implementation specific
class called smanip which provide a mechanism for calling your
function.

smanip setUppercase(bool b)
{
  return smanip(set_uppercase, b);
}

> Secondly, the exqmple completely befuddles me.  I'm guessing that don't
> understand the order of operations of
>
>    cout << setprecision(4) << angle;
>
>    is ostream<< called first and then the function setprecision?

No, it can help if you rewrite it with function call:
operator<<( operator<<(cout ,setprecision(4)) , angle );

--
Michael

[toc] | [prev] | [next] | [standalone]


#7532

FromRuben Safir <ruben@mrbrklyn.com>
Date2011-07-06 15:01 +0000
Message-ID<iv1tcj$mbj$2@reader1.panix.com>
In reply to#7506
On Wed, 06 Jul 2011 02:55:09 +0000, Ruben Safir wrote:

> What don't understand a couple of things here, and this might be an
> accumulation of increasing confusion on my part as I've continued
> through this chapter.

nobody with experience in this?

[toc] | [prev] | [next] | [standalone]


#7541

From"Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com>
Date2011-07-06 19:13 +0200
Message-ID<iv24u2$pbf$1@dont-email.me>
In reply to#7532
* Ruben Safir, on 06.07.2011 17:01:
> On Wed, 06 Jul 2011 02:55:09 +0000, Ruben Safir wrote:
>
>> What don't understand a couple of things here, and this might be an
>> accumulation of increasing confusion on my part as I've continued
>> through this chapter.
>
> nobody with experience in this?

I'm guessing you didn't quite grok Michael's answer?

OK, it's not that hard. You just have to think about how you would have 
implemented the design, where the design is that a manipulator expression such 
as `setWidth(4)` can be "inserted" into the stream. It's a horrible design! :-)

But given that, well, `setWidth(4)` is a function call. As a function call it 
produces some value. That value is inserted into the stream via <<.

So what value should `setWidth(4)` produce?

It must be a value that somehow remembers the `4`, and it must be a value that 
isn't just presented as a number or something.

So, you let it be a value of some special class, like

   struct MyWidthManip
   {
       int w_;
       MyWidthManip( int w ): w_( w ) {}
   };

Now you can define the function `setWidth`:

   MyWidthManip setWidth( int w ) { return MyWidthManip( w ); }

Goodie, your call `setWidth( 4 )` produces an object of this class.

All you have to do now is to define the effect of inserting that into a stream:

   std::ostream& operator<<(
       std::ostream&           stream,
       MyWidthManip const&     m
       )
   {
       stream.setw( m.w_ );    // I'm just assuming there is a setw. Dunno.
       return stream;
   }

And that's it.

For a manipulator without arguments you don't need a supporting class, because 
the manipulator can just be a function that << operator then calls.

Bjarne's example of a support class was a bit more general than above, namely a 
support class that supported many different one-int-argument manipulators. That 
made it a little more complex. With some old C syntax function pointer 
declaration thrown in  --  I don't understand why he would do that in a book!


Cheers & hth.,

- Alf

-- 
blog at <url: http://alfps.wordpress.com>

[toc] | [prev] | [next] | [standalone]


#7542

FromRuben Safir <ruben@mrbrklyn.com>
Date2011-07-06 18:00 +0000
Message-ID<iv27r6$mbj$3@reader1.panix.com>
In reply to#7541
On Wed, 06 Jul 2011 19:13:22 +0200, Alf P. Steinbach /Usenet wrote:


>> nobody with experience in this?
> 
> I'm guessing you didn't quite grok Michael's answer?

I didn't see Michael's answer.  But I'll google for it.

[toc] | [prev] | [next] | [standalone]


#7561

FromRuben Safir <ruben@mrbrklyn.com>
Date2011-07-07 02:51 +0000
Message-ID<iv36vv$j8s$1@reader1.panix.com>
In reply to#7541
On Wed, 06 Jul 2011 19:13:22 +0200, Alf P. Steinbach /Usenet wrote:


>    std::ostream& operator<<(
>        std::ostream&           stream,
>        MyWidthManip const&     m
>        )
>    {
>        stream.setw( m.w_ );    // I'm just assuming there is a setw.
>        Dunno. return stream;
>    }
> 
> And that's it.
> 
> For a manipulator without arguments you don't need a supporting class,
> because the manipulator can just be a function that << operator then
> calls.

what is wrong with 

std::ostream& operator<<(std::ostread& os, flags (*f)(int a)) {
	os.setf(f(a));
}

flags  setw(x){
	return std::ios_base:setw(x);
}

[toc] | [prev] | [next] | [standalone]


#7567

From"Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com>
Date2011-07-07 11:13 +0200
Message-ID<iv3tbl$jc0$1@dont-email.me>
In reply to#7561
* Ruben Safir, on 07.07.2011 04:51:
> On Wed, 06 Jul 2011 19:13:22 +0200, Alf P. Steinbach /Usenet wrote:
>
>
>>     std::ostream&  operator<<(
>>         std::ostream&            stream,
>>         MyWidthManip const&      m
>>         )
>>     {
>>         stream.setw( m.w_ );    // I'm just assuming there is a setw.
>>         Dunno. return stream;
>>     }
>>
>> And that's it.
>>
>> For a manipulator without arguments you don't need a supporting class,
>> because the manipulator can just be a function that<<  operator then
>> calls.
>
> what is wrong with
>
> std::ostream&  operator<<(std::ostread&  os, flags (*f)(int a)) {
> 	os.setf(f(a));
> }
>
> flags  setw(x){
> 	return std::ios_base:setw(x);
> }

Try it. :-)


Cheers & hth.,

- Alf

-- 
blog at <url: http://alfps.wordpress.com>

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c++


csiph-web