|
Boost : |
From: Tom Becker (voidampersand_at_[hidden])
Date: 2001-12-26 17:47:12
On Mon, 24 Dec 2001 12:41:40 -0800, Tom Becker wrote:
>How about if it supports printf syntax? Anything that departs from
>printf syntax is likely to be perceived as a compromise, unless it's
>clearly better. But the main problem with printf is its lack of type
>safety.
This is a follow-up to my own post. I looked through the existing
format, format2 and formatter docs and the main concerns with a
printf-style syntax in C++ seem to be code bloat and dealing with
const variables and references. The other concern is being able to
support a vast number of arguments.
I updated the example from my previous message, to minimize code
bloat. It generates one inline function per type of format(...) call.
It's a relatively short function, so in most cases I think it really
will be inlined. In addition, it generates two functions for each
type of argument, one to push the argument and one to write it. The
arg_writer functions essentially correspond to the % or () or <<
operators in the operator-style syntax. So the overhead required for
the printf-style syntax relative to the alternatives is the inline
function for each call to format, and the function for pushing each
argument type. I think the approach of having a vector of pointers to
arguments may be more efficient than a map of ostringstreams, but it
could be adopted without the printf-style syntax, so it's not a
factor. Nonetheless, I think the overhead for the printf-style syntax
is minimal and reasonable.
As far as I can tell, there aren't any problems with const or
reference types, because I'm not copying any of the arguments
provided, only pointers to them. If it turns out there is some
problem, I'm expecting it could be resolved using type_traits.
There is no way the printf-style approach can support an infinite
number of arguments. However, I don't consider that to be a
significant liability. A maximum of 128 or even 50 arguments ought to
be okay for most applications, and the workaround for larger numbers
is simple.
I hope this addresses people's concerns about a printf-style syntax,
well enough so they will consider supporting it.
Regards,
Tom
#include <iostream>
#include <vector>
using std::ostream;
using std::cout;
using std::endl;
using std::vector;
typedef void (*arg_writer)(ostream& dest, void* arg_ptr);
struct format_arg
{
void* ptr_;
arg_writer writer_;
format_arg(void* ptr, arg_writer writer) :
ptr_(ptr),
writer_(writer)
{
}
};
inline ostream& operator<<(ostream& dest, const format_arg& arg)
{
arg.writer_(dest, arg.ptr_);
return dest;
}
struct format
{
format(const char* s) :
s_(s)
{
}
template<typename T1>
format(const char* s, T1 a1) :
s_(s)
{
push_arg(&a1);
}
template<typename T1, typename T2>
format(const char* s, T1 a1, T2 a2) :
s_(s)
{
push_arg(&a1);
push_arg(&a2);
}
// more constructors for as many arguments as needed
template<typename T>
void push_arg(T* arg)
{
args_.push_back(format_arg(arg, &write_arg<T>));
}
template<typename T>
static void write_arg(ostream& dest, void* arg_ptr)
{
dest << *reinterpret_cast<T*>(arg_ptr);
}
void write(ostream& dest) const
{
// dummy just print the format and args for now
dest << s_;
int n = args_.size();
for (int i = 0; i < n; ++i)
{
dest << " " << args_[i];
}
}
vector<format_arg> args_;
const char* s_;
};
inline ostream& operator<<(ostream& dest, const format& f)
{
f.write(dest);
return dest;
}
int main()
{
short x = 2;
float y = 3.14;
cout << format("%d, %f", x, y) << endl;
const float& yy(y);
cout << format("%d, %f", x, yy) << endl;
return 0;
}
-- Tom Becker "Within C++, there is a much smaller and <voidampersand_at_[hidden]> cleaner language struggling to get out." -- Bjarne Stroustrup
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk