仅使用std :: string的C ++变量参数

时间:2013-09-25 15:29:54

标签: c++11 stdstring variadic-functions printf

我正在尝试创建一个函数,它接受可变数量的std :: string参数并用它格式化一个字符串。

示例:

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;
}

编译此代码段错误:

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

我想要实现的目标:

Test t = Test();
t.formatLine("Hello %s!", "monsieur");

应打印Hello monsieur!

t.formatLine("Hello %s %s! How %s you today?", "good", "sir", "are");

应打印Hello good sir! How are you today?

是否可以仅将va_listvsprintfstd::string一起使用,避免使用char buffer[size]

使用缓冲区:

,使用Igor建议的修复工作示例(到目前为止)
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;
}

使用 Igor Tandetnik 的建议和示例代码我终于得到了一个不使用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 个答案:

答案 0 :(得分:3)

首先,它是buffer.c_str()format.c_str()(注意括号)。

其次,vsprintf的第一个参数应该是足够大小的可修改缓冲区。您正试图将const char*指向一个大一个字节的缓冲区。

您可以使用vector<char>作为缓冲区持有者(很容易调整大小)。问题是,没有办法从vsprintf中获得所需的缓冲区大小。一种技术是分配一些初始缓冲区,然后重复调用vsnprintf(注意'n'),每次函数说它太小时,将缓冲区的大小加倍。

答案 1 :(得分:3)

生产质量答案

#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; }