C++ Iterating Over va_list

Viewed 1735

I'm trying to write a function which works like C#'s String::Format, where instead of taking arguments starting in '%' ("%d %s %i"), it takes arguments like "{0} {1} {2}", and I've gotten it to work (mostly).

It finds and replaces all occurrences correctly, but then breaks when it gets to the end of args. Right before it breaks the debugger shows 'result' getting set to "\f;@" where the final character is a random, "non-standard" character.

Notes**: 'string' is std::string, String::Format1 works correctly and uses vsnprintf_s, and String::Replace finds and replaces all occurrences of find with replace.

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

I recommend not using varargs for the formatting API because they are inherently unsafe. Use variadic templates instead.

The fmt library, which implements text formatting with brace-delimited placeholders ({0}, {1}, ...), uses variadic templates and array initialization to build an array of arguments. Here's a sketch of how it works:

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

where Arg is a variant-like class that is implicitly convertible from formatting argument types:

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

The advantage of this approach is that it has better compile time compared to recursive templates (https://github.com/fmtlib/fmt/pull/243). Also you can easily access arguments by index in array.

Disclaimer: I'm the author of the fmt library.

Related