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.
的作者
我正在尝试编写一个像 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.
的作者