|
Boost : |
From: Sven Van Echelpoel (sven.vanechelpoel.sv_at_[hidden])
Date: 2002-05-15 09:31:03
Oops!
I'm afraid my previous posting contained some inconsistencies.
Of course you can supply additional formatting parameters. I was
thinking about 3 or 4 new solutions while typing. Maybe I shouldn't have
been so hasty :-). Anyhew, here are some more thoughts. Try this syntax
for size:
fmt.format( "Enter a number between %p1 and %p2" )
%p1( 10, Width=10,Fill='#' )
%p2( 100, Width=10,Fill='#' );
And its implementation:
#include "stdafx.h"
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
class format_param;
class manipulator;
class formatter
{
public:
formatter& operator % ( format_param& );
formatter& format( char const* fmt )
{
mResult = fmt;
return ( *this );
}
string const& str()
{
return ( mResult );
}
private:
string mResult;
};
class manipulator
{
public:
virtual void manip_stream( ostringstream & oss ) const = 0;
};
class hex_manipulator :
public manipulator
{
public:
void manip_stream( ostringstream& oss ) const
{
oss.setf( ios_base::hex, ios_base::basefield );
}
};
class width_manipulator :
public manipulator
{
public:
width_manipulator( streamsize width ) :
the_width( width ) {}
void manip_stream( ostringstream& oss ) const
{
oss.width( the_width );
}
private:
streamsize the_width;
};
class make_width_manipulator
{
public:
width_manipulator operator=( streamsize sz ) const
{
return ( width_manipulator( sz ) );
}
};
class fill_manipulator :
public manipulator
{
public:
fill_manipulator( char fill ) :
the_fill( fill ) {}
void manip_stream( ostringstream& oss ) const
{
oss.fill( the_fill );
}
private:
char the_fill;
};
class make_fill_manipulator
{
public:
fill_manipulator operator=( char ch ) const
{
return ( fill_manipulator( ch ) );
}
private:
char the_fill;
};
const make_width_manipulator Width;
const hex_manipulator Hex;
const make_fill_manipulator Fill;
class format_param
{
public:
void replace( std::string& s )
{
string::size_type sidx = s.find( param_id );
if ( string::npos != sidx )
{
string tmp = s.substr( 0, sidx );
tmp += oss.str();
if ( sidx + param_id.length() < s.length() )
{
tmp += s.substr( sidx + param_id.length() );
}
s = tmp;
}
}
protected:
template<typename T>
format_param( T const& val, char const* id ) :
param_id( id )
{
oss << val;
}
template<typename T>
format_param( T const& val, char const* id,
manipulator const& manip ) :
param_id( id )
{
manip.manip_stream( oss );
oss << val;
}
template<typename T>
format_param( T const& val, char const* id,
manipulator const& manip1,
manipulator const& manip2 ) :
param_id( id )
{
manip1.manip_stream( oss );
manip2.manip_stream( oss );
oss << val;
}
template<typename T>
format_param( T const& val, char const* id,
manipulator const& manip1,
manipulator const& manip2,
manipulator const& manip3 ) :
param_id( id )
{
manip1.manip_stream( oss );
manip2.manip_stream( oss );
manip3.manip_stream( oss );
oss << val;
}
// More of these ctrs
private:
string param_id;
ostringstream oss;
};
class p1 : public format_param
{
public:
template<typename T>
p1( T const& t ) :
format_param( t, "%p1" )
{
}
template<typename T>
p1( T const& t, manipulator const& manip ) :
format_param( t, "%p1", manip )
{
}
template<typename T>
p1( T const& t, manipulator const& manip1,
manipulator const& manip2 ) :
format_param( t, "%p1", manip1, manip2 )
{
}
template<typename T>
p1( T const& t, manipulator const& manip1,
manipulator const& manip2,
manipulator const& manip3 ) :
format_param( t, "%p1", manip1, manip2, manip3 )
{
}
// More of these ctrs
};
class p2 : public format_param
{
public:
template<typename T>
p2( T const& t ) :
format_param( t, "%p2" )
{
}
template<typename T>
p2( T const& t, manipulator const& manip ) :
format_param( t, "%p2", manip )
{
}
template<typename T>
p2( T const& t, manipulator const& manip1, manipulator const& manip2 )
:
format_param( t, "%p2", manip1, manip2 )
{
}
template<typename T>
p2( T const& t, manipulator const& manip1, manipulator const& manip2,
manipulator const& manip3 ) :
format_param( t, "%p2", manip1, manip2, manip3 )
{
}
// More of these ctrs
};
formatter& formatter::operator%( format_param& param )
{
param.replace( mResult );
return ( *this );
}
int main(int argc, char* argv[])
{
formatter fmt;
fmt.format( "Enter a number between %p1 and %p2" )
%p1( 10, Width=10,Fill='#' )
%p2( 100, Width=10,Fill='#' );
cout << fmt.str() << endl;
return 0;
}
An alternative would be to separate the formatting options like so:
fmt.format( "Enter a number between %p1 and %p2" )
%p1( 10 ) (Hex, Width=8, Fill='0' )
%p2( 100 );
All we have to do is add a few overloaded operator()'s:
#include "stdafx.h"
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
class format_param;
class manipulator;
class formatter
{
public:
formatter& operator % ( format_param& );
formatter& format( char const* fmt )
{
mResult = fmt;
return ( *this );
}
string const& str()
{
return ( mResult );
}
private:
string mResult;
};
class manipulator
{
public:
virtual void manip_stream( ostringstream & oss ) const = 0;
};
class hex_manipulator :
public manipulator
{
public:
void manip_stream( ostringstream& oss ) const
{
oss.setf( ios_base::hex, ios_base::basefield );
}
};
class width_manipulator :
public manipulator
{
public:
width_manipulator( streamsize width ) :
the_width( width ) {}
void manip_stream( ostringstream& oss ) const
{
oss.width( the_width );
}
private:
streamsize the_width;
};
class make_width_manipulator
{
public:
width_manipulator operator=( streamsize sz ) const
{
return ( width_manipulator( sz ) );
}
};
class fill_manipulator :
public manipulator
{
public:
fill_manipulator( char fill ) :
the_fill( fill ) {}
void manip_stream( ostringstream& oss ) const
{
oss.fill( the_fill );
}
private:
char the_fill;
};
class make_fill_manipulator
{
public:
fill_manipulator operator=( char ch ) const
{
return ( fill_manipulator( ch ) );
}
private:
char the_fill;
};
const make_width_manipulator Width;
const hex_manipulator Hex;
const make_fill_manipulator Fill;
class format_param
{
struct param_value
{
virtual format_value( ostringstream& oss ) const = 0;
};
template<typename T>
struct param_value_impl :
public param_value
{
param_value_impl( T const& t ) :
val( t ) {}
virtual format_value( ostringstream& oss ) const
{
oss << val;
}
private:
T const& val;
};
public:
void replace( std::string& s )
{
value->format_value( oss );
string::size_type sidx = s.find( param_id );
if ( string::npos != sidx )
{
string tmp = s.substr( 0, sidx );
tmp += oss.str();
if ( sidx + param_id.length() < s.length() )
{
tmp += s.substr( sidx + param_id.length() );
}
s = tmp;
}
}
format_param& operator()( manipulator const& manip )
{
manip.manip_stream( oss );
return ( *this );
}
format_param& operator()( manipulator const& manip1, manipulator const&
manip2 )
{
manip1.manip_stream( oss );
manip2.manip_stream( oss );
return ( *this );
}
format_param& operator()( manipulator const& manip1, manipulator const&
manip2, manipulator const& manip3 )
{
manip1.manip_stream( oss );
manip2.manip_stream( oss );
manip3.manip_stream( oss );
return ( *this );
}
~format_param()
{
delete value;
}
// More of these operator()...
protected:
template<typename T>
format_param( T const& val, char const* id ) :
param_id( id ), value ( new param_value_impl<T>( val ) )
{
}
private:
string param_id;
ostringstream oss;
param_value* value;
};
class p1 : public format_param
{
public:
template<typename T>
p1( T const& t ) :
format_param( t, "%p1" )
{
}
};
class p2 : public format_param
{
public:
template<typename T>
p2( T const& t ) :
format_param( t, "%p2" )
{
}
};
formatter& formatter::operator%( format_param& param )
{
param.replace( mResult );
return ( *this );
}
int main(int argc, char* argv[])
{
formatter fmt;
fmt.format( "Enter a number between %p1 and %p2" )
%p1( 10 ) (Width=10,Fill='#' )
%p2( 100 ) (Width=10,Fill='#' );
cout << fmt.str() << endl;
return 0;
}
Or as in my original posting:
fmt.format( "Enter a number between %p1 and %p2" )
%p1( 10 ) [Hex][Width=8][Fill='0']
%p2( 100 );
As you can see there is great freedom in the syntax, with each variant
being a bit more arcane than the previous ones. Maybe things are getting
out of control. I'm also running into problems when I put everyting in a
namespace.
Still, all of this was a nice exercise.
Svenne.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk