I'm trying to create a function that takes a variable amount of std::string arguments and formats a string with it.
Example:
Test::formatLine(const string::format, ...)
{
const std::string buffer;
va_list args;
va_start(args, format);
vsprintf(buffer.c_str, format.c_str, args);
va_end(args);
cout << buffer << endl;
}
Compiling this snippet errors:
Error 1 error C3867: 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>::c_str': function call missing argument list; use '&std::basic_string<char,std::char_traits<char>,std::allocator<char>>::c_str' to create a pointer to member
What I want to achieve:
Test t = Test();
t.formatLine("Hello %s!", "monsieur");
should print Hello monsieur!
t.formatLine("Hello %s %s! How %s you today?", "good", "sir", "are");
should print Hello good sir! How are you today?
Is it even possible to use va_list
and vsprintf
with std::string
only, avoiding char buffer[size]
?
Working example (so far) with fixes suggested by Igor, using buffer:
void Test::formatLine(string format, ...)
{
char buffer[256];
va_list args;
va_start(args, format);
vsprintf_s(buffer, format.c_str(), args);
va_end(args);
cout << buffer << endl;
}
Using Igor Tandetnik's suggestion and sample code I finally got a working example that does not use char buffer[size]:
void Test::formatLine(string format, ...)
{
vector<char> buf(256);
va_list args;
va_start(args, format);
vsnprintf_s(&buf[0], buf.size(), buf.size() + strlen(format.c_str()), format.c_str(), args);
va_end(args);
cout << &buf[0] << endl;
}
A Production Quality Answer
#include <cstdarg>
#include <string>
#include <vector>
// requires at least C++11
const std::string vFormat(const std::string sFormat, ...) {
const char * const zcFormat = sFormat.c_str();
// initialize use of the variable argument array
va_list vaArgs;
va_start(vaArgs, sFormat);
// reliably acquire the size from a copy of
// the variable argument array
// and a functionally reliable call
// to mock the formatting
va_list vaCopy;
va_copy(vaCopy, vaArgs);
const int iLen = std::vsnprintf(NULL, 0, zcFormat, vaCopy);
va_end(vaCopy);
// return a formatted string without
// risking memory mismanagement
// and without assuming any compiler
// or platform specific behavior
std::vector<char> zc(iLen + 1);
std::vsnprintf(zc.data(), zc.size(), zcFormat, vaArgs);
va_end(vaArgs);
return std::string(zc.data(), zc.size()); }
#include <ctime>
#include <iostream>
#include <iomanip>
// demonstration of use
int main() {
std::time_t t = std::time(nullptr);
int i1 = 11; int i2 = 22; int i3 = 33;
std::cerr
<< std::put_time(std::localtime(& t), "%D %T")
<< vFormat(" [%s]: %s {i1=%d, i2=%d, i3=%d}",
"DEBUG",
"Xyz failed",
i1, i2, i3)
<< std::endl;
return 0; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With