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 函数都有重载以支持自定义排序。
我有一个旧的 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 函数都有重载以支持自定义排序。