Reputation: 1454
Very frequently in my C++ code I use the following type of helper function:
static inline std::string stringf(const char *fmt, ...)
{
std::string ret;
// Deal with varargs
va_list args;
va_start(args, fmt);
// Resize our string based on the arguments
ret.resize(vsnprintf(0, 0, fmt, args));
// End the varargs and restart because vsnprintf mucked up our args
va_end(args);
va_start(args, fmt);
// Fill the string
if(!ret.empty())
{
vsnprintf(&ret.front(), ret.size() + 1, fmt, args);
}
// End of variadic section
va_end(args);
// Return the string
return ret;
}
It has a few upsides:
Now, I have a few of problems with it:
Does anybody know a better way?
Upvotes: 5
Views: 2367
Reputation: 5054
As you added the tag c++11
I suppose that you can use it. Then you can simplify your code to this:
namespace fmt {
template< class ...Args >
std::string sprintf( const char * f, Args && ...args ) {
int size = snprintf( nullptr, 0, f, args... );
std::string res;
res.resize( size );
snprintf( & res[ 0 ], size + 1, f, args... );
return res;
}
}
int main() {
cout << fmt::sprintf( "%s %d %.1f\n", "Hello", 42, 33.22 );
return 0;
}
Upvotes: 5
Reputation: 17714
Are you married (pun intended) to std::sprintf()
? If you are using C++ and the oh so modern std::string
, why not take full advantage of new language features and use variadic templates to do a type safe sprintf
that returns a std::string
?
Check out this very nice looking implementation: https://github.com/c42f/tinyformat. I think this solves all your issues.
Upvotes: 5
Reputation: 16146
Don't do the first vsnprintf
with size 0. Instead, use a stack buffer with some probable size (e.g. something between 64 to 4096), and copy that into the return value if it fits.
Your concerns about std::string
's contiguity are misplaced. It is well-defined and perfectly okay to rely on.
Finally - I would like to reecho that a compile-time format-checking library would be better. You need C++14 for full power, but C++11 supports enough that you should be able to #ifdef
some header code without losing any expressive. Remember to think about gettext
though!
Upvotes: 1