iostream vs stdio.h

N

Ningyu Shi

I recently started to write a program in c++, which involves some I/O
of file. Quickly, I found that it's difficult to use the c++ iostream
stuff.
say I want to do
printf("%10.3f %.4f %5d",a,b,c)
in c++
is it right to write like
cout<<setprecision(3)<<setw(10)<<a<<........?
that's too complicated...
I've read a lot of old discussion on this group, still confused, is
there a easier way to do my job in c++ way? I just want some simple
controled data output.
is there a way like
cout<<fmt("%10.3f %.4f %5d")<<a<<b<<c?
thanks
 
S

Stuart Redmann

Ningyu said:
I recently started to write a program in c++, which involves some I/O
of file. Quickly, I found that it's difficult to use the c++ iostream
stuff.
say I want to do
printf("%10.3f %.4f %5d",a,b,c)
in c++
is it right to write like
cout<<setprecision(3)<<setw(10)<<a<<........?
that's too complicated...
I've read a lot of old discussion on this group, still confused, is
there a easier way to do my job in c++ way? I just want some simple
controled data output.
is there a way like
cout<<fmt("%10.3f %.4f %5d")<<a<<b<<c?
thanks

What about the following:

#include <iostream>
#include <sstream>
#include <iomanip>

int StringToInt(std::string stringValue)
{
std::stringstream ssStream(stringValue);
int iReturn;
ssStream >> iReturn;
return iReturn;
}

class decorated_ostream
{
public:
std::string FormatSpecifier;
std::eek:stream* OriginalStream;

decorated_ostream& operator<<(std::eek:stream& (__cdecl *_F)(std::eek:stream&))
{
((*_F)(*OriginalStream));
return *this;
}
};

class ostream_decorator
{
public:
std::string FormatSpecifier;
};

ostream_decorator fmt (const char* Format)
{
ostream_decorator RetVal;
RetVal.FormatSpecifier = Format;
return RetVal;
}

decorated_ostream operator<< (std::eek:stream& p_refLHS, ostream_decorator&
Specifier)
{
decorated_ostream RetVal;
RetVal.OriginalStream = &p_refLHS;
RetVal.FormatSpecifier = Specifier.FormatSpecifier;
return RetVal;
}

template <class T>
decorated_ostream& operator<< (decorated_ostream& p_refLHS, T p_RHS)
{
// If the format specifier is zero, we behave just like an ordinary
ostream.
if (p_refLHS.FormatSpecifier.size () == 0)
{
(*p_refLHS.OriginalStream) << p_RHS;
return p_refLHS;
}

// Search the format specifier for the first format specification.
int Temp = p_refLHS.FormatSpecifier.find_first_of ("%");
if (Temp == std::string::npos)
{
// If we haven't found any '%', we can assume that the format
string can be copied to the underlying
// stream one by one.
(*p_refLHS.OriginalStream) << p_refLHS.FormatSpecifier;
p_refLHS.FormatSpecifier.erase ();
return p_refLHS;
}
else
{
// Print the string before the '%' symbol and process the format
specifier.
(*p_refLHS.OriginalStream) << p_refLHS.FormatSpecifier.substr (0,
Temp);
p_refLHS.FormatSpecifier .erase (0, Temp + 1);

// We only process size specifier and precision of floats and doubles.
int Temp = p_refLHS.FormatSpecifier.find_first_not_of ("0123456789");
if (p_refLHS.FormatSpecifier[Temp] == '.' ||
p_refLHS.FormatSpecifier[Temp] == 'd' ||
p_refLHS.FormatSpecifier[Temp] == 'f')
{
// If Temp is non-zero, the user has supplied a width specifier.
if (Temp > 0)
{
// Parse the integer value and set it as requested width.
(*p_refLHS.OriginalStream) << std::setw (StringToInt
(p_refLHS.FormatSpecifier.substr (0, Temp)));
p_refLHS.FormatSpecifier.erase (0, Temp);
}
}
else
// TODO: do some meaningful error handling here.
throw 0;

// If there is a point in the format specification, we must search
for a precision specification.
if (p_refLHS.FormatSpecifier[0] == '.')
{
p_refLHS.FormatSpecifier.erase (0, 1);
Temp = p_refLHS.FormatSpecifier.find_first_not_of ("0123456789");
if (p_refLHS.FormatSpecifier[Temp] == 'd' ||
p_refLHS.FormatSpecifier[Temp] == 'f')
{
// If Temp is non-zero, the user has supplied a precision
specifier.
if (Temp > 0)
{
// Parse the integer value and set it as requested precision.
(*p_refLHS.OriginalStream) << std::setprecision (StringToInt
(p_refLHS.FormatSpecifier.substr (0, Temp)));
p_refLHS.FormatSpecifier.erase (0, Temp);
}
}
else
// TODO: do some meaningful error handling here.
throw 0;
}

(*p_refLHS.OriginalStream) << p_RHS;
p_refLHS.FormatSpecifier = p_refLHS.FormatSpecifier.erase (0, 1);
return p_refLHS;
}
}

int main ()
{

std::cout << fmt ("test1 %10ftest2 %4.2d") << 3.5 << 3.1416 <<
"test3" << std::endl;
return 0;
}

Above code has some drawbacks, however: only format specifications for
double and floats are recognized, and for these only the width and
precision is parsed. If you should need more, you'd have to modify the
parsing of the format specifiers. Furthermore, no type checking is
performed. This means that a user may specify "%d" but put a string as
next parameter into the decorated_ostream. Of course, you could check
this by retrieving the type of T at run-time and check against the
format specifier. You should keep in mind, that you cannot pass a second
fmt () specification into the call chain, since the second
ostream_decorator would be passed to the underlying stream, but the
resulting new decorated_ostream will be discarded. If you need this
behaviour urgently i'd think of a better solution.

Regards,
Stuart
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top