在C++中,有没有一种更优雅的方法可以将sprintf和std::string结合起来
Is there a more elegant way of marrying sprintf and std::string in C++?
在我的C++代码中,我经常使用以下类型的辅助函数:
static inline std::string stringf(const char *fmt, ...)
{
std::string ret;
// Deal with varargs
va_list args;
va_start(args, fmt);
// Resize our string based on the arguments
ret.resize(vsnprintf(0, 0, fmt, args));
// End the varargs and restart because vsnprintf mucked up our args
va_end(args);
va_start(args, fmt);
// Fill the string
if(!ret.empty())
{
vsnprintf(&ret.front(), ret.size() + 1, fmt, args);
}
// End of variadic section
va_end(args);
// Return the string
return ret;
}
它有几个优点:
- 字符串长度没有任意限制
- 字符串是在适当的位置生成的,不会被复制(如果RVO正常工作)
- 外界不会感到意外
现在,我有几个问题:
- 重新扫描varargs有点难看
- std::string在内部是一个连续的字符串,后面有一个null终止符的空间,这一事实似乎并没有在规范中明确说明。这是通过->c_str()必须是O(1)并返回一个null结束符的字符串来暗示的,我相信&(data()[0])应该等于&(*begin())
- vsnprintf()被调用两次,第一次可能会做昂贵的一次性工作
有人知道更好的方法吗?
你和std::sprintf()
结婚了吗?如果你使用的是C++和非常现代的std::string
,为什么不充分利用新的语言功能,使用可变模板来创建一个返回std::string
的类型安全的sprintf
呢?
看看这个非常好看的实现:https://github.com/c42f/tinyformat.我认为这解决了你所有的问题。
当您添加标签c++11
时,我想您可以使用它。然后您可以将代码简化为:
namespace fmt {
template< class ...Args >
std::string sprintf( const char * f, Args && ...args ) {
int size = snprintf( nullptr, 0, f, args... );
std::string res;
res.resize( size );
snprintf( & res[ 0 ], size + 1, f, args... );
return res;
}
}
int main() {
cout << fmt::sprintf( "%s %d %.1fn", "Hello", 42, 33.22 );
return 0;
}
http://ideone.com/kSnXKj
不要执行大小为0的第一个vsnprintf
。相反,使用一个可能大小(例如64到4096之间)的堆栈缓冲区,如果合适的话,将其复制到返回值中。
你对std::string
的邻接性的担忧是错误的。它定义明确,完全可以依赖。
最后,我想重申,编译时格式检查库会更好。您需要C++14才能获得完整的功能,但C++11支持的内容足够多,您应该能够在不丢失任何表现力的情况下#ifdef
一些头代码。不过,记得想想gettext
!
相关文章:
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用std::函数映射对象方法
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- C++从另一个类访问公共静态向量的正确方法是什么
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 没有为自己的结构调用列表推回方法
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- C++Arduino,在带有char指针参数的方法中使用sprintf,破坏了程序
- 在C++中,有没有一种更优雅的方法可以将sprintf和std::string结合起来
- 用sprintf打印十六进制值的便携式方法