Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #7506 > unrolled thread
| Started by | Ruben Safir <ruben@mrbrklyn.com> |
|---|---|
| First post | 2011-07-06 02:55 +0000 |
| Last post | 2011-07-07 11:13 +0200 |
| Articles | 7 — 3 participants |
Back to article view | Back to comp.lang.c++
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
| From | Ruben Safir <ruben@mrbrklyn.com> |
|---|---|
| Date | 2011-07-06 02:55 +0000 |
| Subject | iostream 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]
| From | Michael DOUBEZ <michael.doubez@free.fr> |
|---|---|
| Date | 2011-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]
| From | Ruben Safir <ruben@mrbrklyn.com> |
|---|---|
| Date | 2011-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]
| From | "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> |
|---|---|
| Date | 2011-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]
| From | Ruben Safir <ruben@mrbrklyn.com> |
|---|---|
| Date | 2011-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]
| From | Ruben Safir <ruben@mrbrklyn.com> |
|---|---|
| Date | 2011-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]
| From | "Alf P. Steinbach /Usenet" <alf.p.steinbach+usenet@gmail.com> |
|---|---|
| Date | 2011-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