vsprintf的{std :: string aware选项

时间:2017-05-22 11:40:57

标签: c++ variadic-functions

我在C(> 80k行)中有一个旧的MUD代码库,它使用printf样式的字符串格式。它很普遍 - 几乎所有文本都通过调用sprintf或vsprintf周围的包装来运行。但是,我最近已经开始使用g ++进行编译以利用STL,并且希望使用std :: string(实际上是一个派生类用于默认的不区分大小写的比较),这是有意义的。

显然,你不能将std :: string作为任何printf函数的可变参数之一传递:我在每种情况下都需要.c_str()。我不想这样做,主要是因为 我不想修改2000多次对printf函数的调用 。我的问题是: 如何创建一个std :: string aware vsprintf

我看到它的方式,我有两个选择:编写我自己的printf函数,在传递到std ::之前迭代通过将指针更改为std :: string到std :: string.data(或c_out())的参数vsprintf,或者我可以借用printf的内容并自己滚动。显然,第一种选择听起来不那么重要。

当然,更好的选择是如果有人之前已经这样做了,但我的谷歌搜索没有任何结果。关于什么是最佳选择的任何提示?

编辑: 这个问题被关闭为How to use C++ std::ostream with printf-like formatting?的副本,我不相信这个问题的答案。我不问如何使用std :: ostream输出字符串与旧的C printf。我正在寻求有关旧C代码库的补丁解决方案的帮助,该解决方案广泛使用sprintf / vsprintf,而无需重写对这些函数的数千次调用以使用输出流。

2 个答案:

答案 0 :(得分:1)

您可以制作自己的printf包装,从char const*中提取std::string。 E.g:

#include <iostream>
#include <string>
#include <cstdio>

template<class T>
inline auto to_c(T&& arg) -> decltype(std::forward<T>(arg)) {
    return std::forward<T>(arg);
}

inline char const* to_c(std::string const& s) { return s.c_str(); }
inline char const* to_c(std::string& s) { return s.c_str(); }

template<class... Args>
int my_printf(char const* fmt, Args&&... args) {
    return std::printf(fmt, to_c(args)...);
}

int main() {
    std::string name = "World";
    my_printf("Hello, %s!\n", name);
}

或者,更好的是,切换到现代C ++格式库,例如fmt

答案 1 :(得分:0)

常见建议是Boost.Format

以他们为榜样:

// printf directives's type-flag can be used to pass formatting options :
std::cout <<  format("_%1$4d_ is : _%1$#4x_, _%1$#4o_, and _%1$s_ by default\n")  % 18;
//          prints  "_  18_ is : _0x12_, _ 022_, and _18_ by default\n"

现在假设为std::ostream&,因此您需要std::stringstream来使用std::string作为后备缓冲区。

PS。使用派生类进行不区分大小写的比较听起来像是一个等待咬你的坏主意。你只需要一个自定义订单;所有假定排序的STL函数都有重载以支持自定义排序。