C++ 遍历 va_list

C++ Iterating Over va_list

我正在尝试编写一个像 C#'s String::Format, where instead of taking arguments starting in '%' ("%d %s %i") 一样工作的函数,它接受像 "{0} {1} {2}" 这样的参数,而且我已经让它工作了(大部分)。

它正确地找到并替换了所有出现的地方,但是当它到达 args 的末尾时就中断了。在它中断之前,调试器显示 'result' 设置为“\f;@”,其中最后一个字符是随机的 "non-standard" 字符。

注意**:'string' 是 std::string,String::Format1 工作正常并使用 vsnprintf_s,并且 String::Replace 查找并将所有出现的 find 替换为替换。

string String::Format2(const string format, ...)
{
    string output = format;

    va_list args;
    va_start(args, format);
    {
        uint i = 0;
        while (args[i] != NULL)
        {
            string find = String::Format1("{%i}", i);

            // Breaks here
            string replace = va_arg(args, const char*);

            output = String::Replace(output, find, replace);

            i++;
        }
    }
    va_end(args);

    return output;
}

感谢@Justin 的评论,为我指明了正确的方向。

我使用了可变参数模板,它似乎可以正常工作:)

找到我的答案

template<typename T, typename ... Args>
static string Format3(const string fmt, const T& first, const Args&... args)
{
    std::stringstream stream;

    stream << first << std::endl;

    int sink[] = { 0, ((void)(stream << args << std::endl), 0)... };

    (void)sink;

    string  out = fmt;
    uint    pos = 0;

    while (stream.good())
    {
        string find = String::Format1("{%i}", pos);

        string replace;

        stream >> replace;

        out = String::Replace(out, find, replace);

        pos++;
    }

    return out;
}

我建议不要对格式使用可变参数 API,因为它们本质上是不安全的。请改用 variadic templates

fmt library,它使用大括号分隔的占位符({0}{1}、...)实现文本格式化,使用可变参数模板和数组初始化来构建一个数组争论。这是它如何工作的草图:

template <typename... Args>
std::string format(std::string_view format_str, const Args&... args) {
  Arg array[] = {args...};
  // Format arguments and return a string.
}

其中 Arg 是一个类似变体的 class,它可以从格式化参数类型隐式转换:

class Arg {
public:
  Arg(int value);
  Arg(double value);
  // ...
};

这种方法的优点是与递归模板 (https://github.com/fmtlib/fmt/pull/243) 相比,它具有更好的编译时间。您还可以通过 array.

中的索引轻松访问参数

免责声明:我是 fmt library.

的作者