std::string vsprintf 的感知选项

std::string aware options for vsprintf

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

显然,您不能将 std::string 作为可变参数之一传递给任何 printf 函数:我在每种情况下都需要 .c_str() 。我不想那样做,主要是因为 我不想修改对 printf 函数的 2000 多次调用。我的问题是:我怎样才能使 std::string 知道 vsprintf?

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

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

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

您可以制作自己的 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("_%1d_ 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。使用派生的 class 进行不区分大小写的比较听起来像是一个坏主意等着咬你。您只需要定制订单;所有假定排序的 STL 函数都有重载以支持自定义排序。