格式化字符串,带有可变大小的参数向量(例如,将参数向量传递给std :: snprintf)

时间:2019-08-24 23:39:28

标签: c++ printf

我正在寻找一种使用可变大小的变量向量格式化字符串的方法。您建议这样做的最好方法是什么?

我已经知道std :: snprintf和std :: vsnprintf,但是不幸的是,没有一个可以解决我的问题。同样,使用递归模板的解决方案对我也不起作用,因为我不能依赖在编译时完全定义输入格式。

这是我要实现的功能的示例接口。

event.preventDefault()

示例输入和输出:

event.stopPropagation()

format_variable_size将返回

std::string format_variable_size(const char* format, const std::vector<int>& in) {
std::string out{};
....
return out;
}

另一个例子:

const char* format = "My first int is %d, my second int is: %d, my float is: %d";
std::vector<int> in = {1,2,3};

format_variable_size将返回

out = "My first int is 1, my second int is: 2, my float is: 3"

谢谢

3 个答案:

答案 0 :(得分:1)

如果您不反对使用fmt,我认为以下方法可能会起作用:

#include <numeric>

std::string format_variable_size(const char* fmt, std::vector<int> args){
  return std::accumulate(
    std::begin(args),
    std::end(args),
    std::string{fmt},
    [](std::string toFmt, int arg){
      return fmt::format(toFmt, arg);
    }
  );
}

std::vector<int> v = {1,2,3};
std::cout << format_variable_size("[{}, {}, {}]\n", v);

答案 1 :(得分:0)

如果您使用的唯一说明符是%d,则可以轻松地执行循环并用向量中的值手动替换。另外,您可以考虑定义自己的替换令牌(例如###)以简化解析。

此外,如果您可以使用相对较小的向量大小(例如最大数目),则可以执行以下操作:

std::vector<int> copy(in);
copy.resize(10);
std::snprintf(buffer, buffer_size, 
    copy[0], copy[1], copy[2], copy[3], copy[4],
    copy[5], copy[6], copy[7], copy[8], copy[9]);
  • 如果格式化字符串所包含的%d小于所传递矢量的大小,则仅输出第一个。
  • 如果大小完全匹配,您将获得预期的结果。
  • 如果%d的数量大于输入向量且不超过副本的大小,则将输出额外的%d,其值为0。
  • 如果%d太多,则行为是不确定的。
    • 如果格式字符串是内部的,则可以接受,但是如果它来自用户或文件,则最好对字符串进行验证(在这种情况下,手动处理可能会很有吸引力)

答案 2 :(得分:0)

不是很好的解决方案,因为我们在编译时无法获得std::vector的大小:

template <std::size_t... I>
std::string
format_variable_size_impl(const char* format, const std::vector<int>& in, 
                          std::index_sequence<I...>)
{
    // Determine the necessary buffer size
    auto size = std::snprintf(nullptr, 0, format, in[I]...);
    std::string out(size + 1, 0);
    std::sprintf(out.data(), format, in[I]...);
    return out;
}

std::string 
format_variable_size(const char* format, const std::vector<int>& in) 
{
    if (in.size() == 0)
        return format;
    if (in.size() == 1)
        return format_variable_size_impl(format, in, std::make_index_sequence<1>{});
    if (in.size() == 2)
        return format_variable_size_impl(format, in, std::make_index_sequence<2>{});
    if (in.size() == 3)
        return format_variable_size_impl(format, in, std::make_index_sequence<3>{});
    if (in.size() == 4)
        return format_variable_size_impl(format, in, std::make_index_sequence<4>{});
    if (in.size() == 5)
        return format_variable_size_impl(format, in, std::make_index_sequence<5>{});
    // ...
}