Isn't this, or can't this be, assuming int x;
std::cout << (x >= 0 ? std::string(' ') : std::string());
std::cout << x;
Or have I missed something?
Or even:
std::cout << std::string( x >= 0, ' ' ) << x ;
Good catch. (Of course, it's not quite the same thing, if e.g.
instead of x, you're calling some expensive function.)
[...]
I'm not familiar with 'Gabi'. Is that part of the standard?
No. But the standard doesn't forbid you from writing your own
classes. The standard manipulators (with the exception,
perhaps, of setw) are really designed more to be examples, than
to be used directly. In normal coding, you don't want to say:
use such and such physical format. You want to say, use the
format appropriate for something with the X semantics, and then
define that format in one, centralized location.
Adding to the snippet above,
const int x = 123;
const int y = 0xabcd;
my compiler produces,
123: 0x00abcd
for the OP's printf statement.
I know. You can't directlyl produce the format I want with
either printf or ostream.
What you can do with ostream is define a new type that outputs
with whatever format you want, and use that. Something like:
class HexInt
{
public:
explicit HexInt( unsigned i ) : myI( i ) {}
friend std:
stream&
operator<<( std:
stream& dest,
HexInt obj )
{
Gabi::IOSave s( dest ) ;
dest.fill( '0' ) ;
dest.setf( std::ios::hex, std::ios::basefield ) ;
dest.setf( std::ios::uppercase ) ;
dest << "0x" << std::setw( 8 ) << obj.myI ;
return dest ;
}
private:
unsigned myI ;
} ;
One might argue that it's wordier than necessary, but it's still
pretty easy. And it definitely keeps all of the code in one
place---the day where your boss says that all hex output must
use lower case, you don't have to change upteen-dozen printf
formats; you just change this one class.
This is an important feature of ostream. Once you've used it,
you realize that anything not supporting it is simply
unacceptable. (As I said, I've not used boost::format to be
sure. But I think you could use something like this with it,
e.g.:
std::cout << boost::format( "%2$s %1$x" )
% HexInt( myInt ) % myString << std::endl ;
. I seem to recall reading that there is even a simpler format,
for such cases: no %n$f, but just something like {1} {2}.)
I can't tell from reading the only draft copy of a C standard
I have, but I'm going to guess that the '%#08x' format width
calculations include the '0x'. Assuming that in the OPs
snippet x and y were meant to be int and sizeof(int) is 4 and
the number of bits per char is 8, I wonder if the OP meant
'%#010x'?
He meant '%#08x'. That's what I meant by having to deal with a
baroque language within a language: that parses:
% start a format specifier
# use alternative format (for integral types, show
base, for other types, something else entirely)
0 use 0 as a fill character
8 output a minimum of 8 characters
x use hexadecimal, with lower case letters.
So using plain old cout, what's wrong with,
std::cout
<< std::dec
<< std::setw(3)
<< x
<< ": "
<< (y == 0 ? std::string() : std::string("0x")) << std::setfill('0')
<< std::setw(6) // or std::setw(8) if you wanted 8 hex digits
<< std::hex
<< y
<< std::endl;
Several things:
-- the next code probably isn't expecting to output in hex:
you've got to reset the format to whatever it was
previously,
-- it's a lot worder than it should be, and
-- you're specifying the physical formatting (rather than the
logical formatting) in the output statement.
Using your own manipulator (which, correctly designed, restores
the formatting state at the end of the full expression), you
solve all three of these problems.
With printf, the first is automatically solved. The second is
solved, but at the cost of using a baroque language within a
language which no one really knows. And it's very, very
difficult to solve the third---you'd need to write something
like:
printf( (std::string( "some text " )
+ hexFmt
+ " whatever).c_str(), variable ) ;
And of course, you have all of the disadvantages of printf: if
hexFmt actually specifies an unsigned long, and your variable is
of type int, you're in trouble, and you can't very well extend
it for your own types (e.g. BigDecimal).
I suppose it would be superfluous to mention std::uppercase.
Which would result in "0X0000ABCD".
I'm not sure I understood the OP's question or your response.
What am I missing, please?
Probably a deep knowledge of the printf nested language. (I
know it because I've actually implemented printf on one
occasion.)
More importantly, like most people, you probably don't
understand the importance of using custom manipulators. The
iostream is a framework which allows you to create much more
powerful things. I don't think I've ever written an application
without a few custom streambuf's (especially filtering
streambufs), and which didn't use custom manipulators and custom
formatting/parsing types almost exclusively.