在這篇博文裏,我提到了一個例子,說的是使用C++實現類型安全的printf。這個例子很驚豔,可是在我寫程序的時候,並不是那麼「迫切」地須要它出如今個人工具箱中,由於它並不比普通的printf方便,並且它沒有出現的標準庫中。因此本身也懶得整。相反,這個函數的兄弟,sprintf,卻是一個很是須要的函數。不單單是由於須要它類型安全,而是 sprintf 有比 printf 更多的麻煩:html
這很是的麻煩,可是,sprintf 緊湊的表達是它最大的優勢~我纔不會用流去格式化一個字符串呢,實在是讓人精神分裂啊。安全
想到用 variadic template 實現的 printf 以後,以爲應該是徹底能夠模仿這個作一個 sprintf 函數的啊,除了獲得類型安全的好外以外,還能直接從函數返回字符串,又不會有溢出的問題,string和流自動地把內存管理好。一舉多得。編輯器
std::string sprintf(const char *s) { std::stringstream ss; _sprintf(ss, s); return ss.str(); } void _sprintf(std::stringstream & ss, const char *s) { while (*s) { if (*s == '%') { if (*(s + 1) == '%') { ++s; } else { throw std::runtime_error("invalid format string: missing arguments"); } } ss << *s++; } } template<typename T,typename... Args> std::string sprintf(const char *s, T value, Args... args) { std::stringstream ss; _sprintf(ss, s, value, args...); return ss.str(); } template<typename T, typename... Args> void _sprintf(std::stringstream & ss, const char *s, T value, Args... args) { while (*s) { if (*s == '%') { if (*(s + 1) == '%') { ++s; } else { ss << value; _sprintf(ss, s + 1, args...); // call even when *s == 0 to detect extra arguments return; } } ss << *s++; } throw std::logic_error("extra arguments provided to lyw::sprintf"); }
使用起來也很方便,直接像原來的sprintf同樣用就行了。並且若是自定義的對象實現的流操做符重載,就能夠自動地與這個函數配合。很是精巧。ide
string str = sprintf("I tried % times in % ", 10, "Monday");
只須要加一點點代碼(使用C++的流控制符),就能夠實現各加精細的格式,這個版本我就再也不貼了。函數
PS: 代碼在VS2013上跑,很High,工具
VS2013在C++的開發環境(我是指編輯器)上作了很大的改進,並且速度也快了。算是可貴spa