std::VSPRINTF 的字符串感知选项

std::string aware options for vsprintf

本文关键字:感知 选项 字符串 VSPRINTF std      更新时间:2023-10-16

我有一个旧的 C(>80k 行)的 MUD 代码库,它使用 printf 风格的字符串格式。 它是普遍的 - 几乎每个文本都通过对sprintf或vsprintf包装器的调用运行。 但是,我最近转向使用 g++ 进行编译以利用 STL,并希望在有意义的地方使用 std::string(实际上是默认不区分大小写的比较的派生类)。

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

在我看来,我有两个选择:编写我自己的printf函数,在传递给std::vsprintf之前迭代参数,将指向std::string的指针更改为std::string.data(或c_out()),或者我可以借用printf的胆量并滚动我自己的。 显然,第一种选择听起来工作量更少。

当然,更好的选择是如果有人以前做过,但我的谷歌搜索一无所获。 关于最佳选择的任何提示?

编辑: 这个问题被关闭为"如何使用C++std::ostream与类似printf的格式?"的副本,我认为它不能回答这个问题。 我不是在问如何使用 std::ostream 与旧的 C printf 输出字符串。 我正在寻求有关旧 C 代码库的补丁解决方案的帮助,该代码库广泛使用 sprintf/vsprintf,而无需重写对这些函数的数千次调用以使用输出流。

您可以制作自己的printf包装器,从std::string中提取char const*。 例如:

#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.

常见的建议是 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 defaultn")  % 18;
//          prints  "_  18_ is : _0x12_, _ 022_, and _18_ by defaultn"

现在这假设std::ostream&,因此您需要一个std::stringstream才能使用std::string作为支持缓冲区。

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