Click here to Skip to main content
Click here to Skip to main content
Go to top

basic_oformatstream template class

, 13 Nov 2001
Rate this:
Please Sign up or sign in to vote.
Old style printf format strings ported to an ostream shim class
<!-- Download Links --> <!-- Main HTML starts here -->

Introduction

I'm quite sure there will be some who will ask "Why did you build this ?". Yes, it is slower than printf and a little fatter than STL wcout, but...

There are two major reasons I built this template class, apart from the learning experience.

On the one hand I find the STL manipulators to be cumbersome, on the other, the printf family of functions have a major drawback, they don't allow arbitrary growth of the output string.

I could have wrapped only the ostrstream class but that would have unnecessarily limited the use of this template for other kinds of output, namely file and console.

The main template class, basic_oformatstream, acts as a shim ("something thin placed between two parts to make a fit") between the user and the ostream the object is tied to.

WARNING: There is a bug in the VC++ 6.0 STL implementation from Dinkumware.

See the end of file oformatstream.cpp for a short description of the bug (with code). An initial fix is to make the buffer size much larger in  <xlocnum> template num_put functions virtual _OI do_put(_OI _F, ios_base& _X, _E _Fill, double _V) const and virtual _OI do_put(_OI _F, ios_base& _X, _E _Fill, long double _V) const. If making this kind of change to a standard template library file fills you with dread, I don't blame you, so if you can't or won't fix this then never ever try to output a really big floating point value without using the scientific format, ie. %e or %g, the other one %f could cause you grief.

So how do you use it ?

First construct an oformatstream by giving it a format and an output stream to write to. Then it is just a matter of outputting values to the resulting oformatstream. The order in which you send the output values is, as you should expect, utterly dependent upon the order that you specify in the format string.

You can change the format string by using the reformat manipulator which takes a basic_formatter object as it's argument.

formatter f("%8d %6.2f");
oformatstream ofs("%8x %5.3e",&std::cout);

ofs <<  reformat(f);

Note that formatter and oformatstream are typedefs similar in purpose to those done for cout and wcout. In case you were wondering, woformatstream and wformatter are the wide equivalents.

// Example usage:
//
// First a really simple situation: 
oformatstream ofs("[%s] [%8d] [%6.5f]\n", &std::cout);
ofs << "example" << 1 << 3.141592 << setformat;

// Note setformat is used to make sure the last field is output.
// The last field ? Yes the "]\n" text.
// You could also drop the '\n' and use the endl inserter instead.
// This would result in the following code.
oformatstream ofs("[%s] [%8d] [%6.5f]", &std::cout);
ofs << "example" << 1 << 3.141592 << setformat << endl;

// A slightly more complex example: 

// Set up a custom default format specification first 
format_specification fs(12 /*width*/,2/*precision*/,std::ios_base::dec); 

// Generate a formatter with this default format specification 
formatter format("[%s] [%d] [%f]", fs);

 // Construct the oformatstream with this custom formatter 
oformatstream ofs(format, &std::cout); 
ofs << "example" << 1 << 3.141592 << endl;

For some really complex examples see TestFormat.cpp in the demo

The following are more detailed descriptions of the template classes and the various implementation classes and functions you will find if you dig around inside oformatstream.hpp

basic_oformatstream

constructors

The default constructor. Will require a call to tie() before output will work
basic_oformatstream()

Use a format string to construct the internal format field vector
basic_oformatstream(const std::basic_string<_E,_Tr>& s, _Myostream *os = NULL)

Use a preconstructed basic_formatter which allows for a custom default format specification
basic_oformatstream(const basic_formatter<_E>& f, _Myostream *os = NULL)

public methods

Inserter operators
_Myt& operator<<(T) for T= {bool,int,long,...etc.}

Sets the internal formatter
void formatter(constbasic_formatter<_E,_Tr>& f)

Returns the internal formatter
basic_formatter<_E>& formatter()

Ties to an output stream
void tie(_Myostream *os)

Returns the tied output stream
_Myostream* get_ostream()

Sets the default format specification
void default_format_specification(const format_specification& f)

Returns the default format specification
format_specification default_format_specification()

plus several others which are used internally but need to be public

basic_formatter

constructors

The default constructor
basic_formatter()

Supply a default format specification
basic_formatter(const format_specification fs)

Use a format string
basic_formatter(std::basic_string<_E,_Tr> fs)

Use a format string and supply a default format specification
basic_formatter(std::basic_string<_E,_Tr> s, const format_specification& fs)

Implementation Classes

format_flags

Manages changes to a std::ios_base::fmtflags value. Enforces restrictions such as hex,dec and oct being mutually exclusive flags.
Provides operators |=, &=, = and various constructors and conversion operators.

format_specification

A single field's format specification corresponds to a single field ie. "%7.5f"

TEMPLATE CLASS format_characters

Provides a central place for storing constants required by the parsing routines. Currently _E may be either char or wchar_t.

TEMPLATE CLASS basic_formatterfield

Holds the final results of parsing a single field's format specification. These being a prefix text string and format specification for the field.

TEMPLATE CLASS FormatFieldVector

derived from std::vector< basic_formatterfield<_E,_Tr>> 

Parsing routines

std::ios_base::fmtflags format_flag_from_char<_E>(const _E ch)

Converts the type character [cdefgisx] into appropriate ios_base flag values.

bool parse_format_specification<_E>(

std::basic_string<_E>::const_iterator& it,

std::basic_string<_E>::const_iterator& end,

format_specification& outfs, bool& widthset, bool& precset, _E& fillchar)

Called by parse_field<_E>() to process a single field's format specification. ie. everything after the percent (%) symbol.

bool parse_field <_E>(

std::basic_string<_E>::const_iterator& it,

std::basic_string<_E>::const_iterator& end,

basic_formatterfield<_E>& outff,

format_specification& default_fs)

Called by parse_format<_E> to process a format field. ie. The prefix text followed by a format specification. Calls parse_format_specification<_E>()

bool parse_format<_E>(

std::basic_string<_E>fs,

FormatFieldVector<_E>& ffv,

format_specification& default_fs)

Used by basic_formatter<_E> constructors to process a full format specification. Calls parse_field<_E>() to build a basic_formatterfield which it then stores in a FormatFieldVector.

Format output management classes

TEMPLATE CLASS basic_formatter

The format of each field is controlled by the given format string.

TEMPLATE CLASS basic_oformatstream

Outputs values to the connected stream (does nothing if not). The internal basic_formatter object controls the layout of each output field and the order that they are expected. No exceptions are thrown if the supplied field type does not match the expected format. The output will probably just look awful.

I have also included StrENUM.h which is a collection of macros to make nice little enumeration to string converter functions.
Here is an example of it's use.

In a .cpp file

// Declares StrIOS_BASE_FORMAT_FLAGS()
BEGIN_STR_ENUM_FUNC( IOS_BASE_FLAGS )
STR_ENUM_FLAG( std::ios_base::uppercase )
STR_ENUM_FLAG( std::ios_base::showbase )
STR_ENUM_FLAG( std::ios_base::showpoint )
STR_ENUM_FLAG( std::ios_base::showpos )
STR_ENUM_FLAG( std::ios_base::left )
STR_ENUM_FLAG( std::ios_base::right )
STR_ENUM_FLAG( std::ios_base::internal )
STR_ENUM_FLAG( std::ios_base::dec )
STR_ENUM_FLAG( std::ios_base::oct )
STR_ENUM_FLAG( std::ios_base::hex )
STR_ENUM_FLAG( std::ios_base::scientific )
STR_ENUM_FLAG( std::ios_base::fixed )
STR_ENUM_FLAG( std::ios_base::boolalpha )
STR_ENUM_FLAG( std::ios_base::skipws )
STR_ENUM_FLAG( std::ios_base::unitbuf )
END_STR_ENUM_FUNC

and in the calling source file

#include "StrENUM.h"
typedef std::ios_base::_Fmtflags IOS_BASE_FLAGS;
DECLARE_STR_ENUM_FUNC( IOS_BASE_FLAGS );
//

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

David 'dex' Schwartz
Team Leader
Australia Australia
Developing various kinds of software using C/C++ since 1984 or so. Started out writing 8086 asm for direct screen i/o and mouse handling etc.
Used several other languages eg. Java, Python, Clipper/dBase, FORTRAN 77, Natural ADABAS, Unix scripting, etc.
My current work involves Enterprise Content Management on Win32.

Comments and Discussions

 
QuestionWhat really is Adabas? PinmemberJon Bravo09829-Apr-12 20:10 
AnswerRe: What really is Adabas? PinmemberDavid 'dex' Schwartz29-Apr-12 22:50 
GeneralNice PinmemberHilmi5-Aug-09 16:14 
GeneralExcellent work PinmemberDavid White19-Mar-09 10:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140926.1 | Last Updated 14 Nov 2001
Article Copyright 2001 by David 'dex' Schwartz
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid