"Type-safe" sprintf
Hello!
I have invented a simple sprintf-like function aimed at replacing sprintf.
The reason being that our code has a lot of dangerous sprintf's that nobody
here is interested in re-writing.
Here is the implementation of my sprintf-like function. It builds on
boost::format. This function is typesafe and provides error checking. It
will throw an exception if the output buffer is overrun, or there weren't
enough arguments.
What do you think?
#include <iostream>
#include <algorithm> // copy
#include <stdexcept> // std::logic_error
#include <string> // std::basic_string
#include <boost/format.hpp> // boost::basic_format
namespace cool
{
namespace detail
{
template<class Char>
class feeder
{ };
template<class Char, std::size_t N>
class feeder<Char[N]>
{
typedef typename boost::basic_format<Char> format_type;
typedef typename std::basic_string<Char> string_type;
format_type format;
Char* buffer;
bool first;
public:
feeder(Char* b)
: buffer(b),
first(true)
{ }
~feeder()
{
// I know it is bad to throw from destructor...
string_type result = str(format);
if( result.size()>=N )
throw std::logic_error("too many arguments to sprintf");
std::copy(result.begin(), result.end(), buffer);
buffer[result.size()] = 0;
}
//! Might be the format string
feeder& operator%(const Char* c)
{
if( first )
{
format.parse(c);
first = false;
}
else
{
format % c;
}
return *this;
}
//! Can never be the format string
template<class T>
feeder& operator%(const T& c)
{
if( first )
{
throw std::logic_error("bad format string");
}
else
{
format % c;
}
return *this;
}
};
}
template<class Source>
typename detail::feeder<Source> sprintf(Source& buffer)
{
typedef typename detail::feeder<Source> Feeder;
return Feeder(buffer);
}
}
int main()
{
char buffer[1024];
cool::sprintf(buffer) % "%d.%d" % 5 % 1;
std::cout << "buffer=" << buffer << std::endl;
char temp[1024];
const int triangle_number = 15;
cool::sprintf(temp) % "71....+TRI%013d " % triangle_number;
std::cout << "temp=" << temp << std::endl;
try
{
cool::sprintf(temp) % "71....+TRI%013d ";
}
catch( std::exception& ex )
{
std::cerr << ex.what() << std::endl;
}
wchar_t wideBuffer[10];
cool::sprintf(wideBuffer) % L"%d.%d" % 5 % 1;
std::wcout << "wideBuffer=" << wideBuffer << std::endl;
return 0;
}
This prints:
buffer=5.1
temp=71....+TRI0000000000015
boost::too_few_args: format-string refered to more arguments than were
passed
wideBuffer=5.1
--
Daniel
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?