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;
}
有帮助吗?

解决方案 2

First, it's buffer.c_str() and format.c_str() (note the parentheses).

Second, the first parameter of vsprintf should be a modifiable buffer of sufficient size. You are trying to pass a const char* pointing to a buffer just one byte large.

You could use vector<char> as a buffer holder (it's easy to resize). The problem is, there's no way to get the required buffer size out of vsprintf. One technique is to allocate some initial buffer, then call vsnprintf (note the 'n') repeatedly, doubling the size of the buffer every time the function says it's too small.

其他提示

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; }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top