C++11:变长参数模板模拟java.lang.String.format格式化输出

原创 2016年08月29日 17:45:30

java.lang.String中有一个很方便的方法format,可以将不同的类型的参数格式化输出成字符串,在C++下面并没有这么方便的函数来支持这个需求。
于是我用C++11的变长参数模板实现了String.format的简单模拟,完整代码如下:
string_utils.h

#pragma once
#include <string>
#include <cstdio>
#include <vector>
#include <regex>
#include <stdexcept>
namespace std {
    /*
     * 简单模拟java.ang.String.format输出
     * 除算术类型(int,long,float等)之外只支持std::string输出
     * */
    class string_utils
    {
        // 普通类型直接返回值
        template<typename T>
        static T cvalue(T&& v){
            return std::forward<T>(v);
        }
        // std::string类型返回c-string指针
        static const char* cvalue( std::string& v){
            return v.c_str();
        }

        // 递归结束
        static int snprintf (char *__stream, size_t __n, const std::string &__format){
            if(__n<=0)return 0;
            // 正则表达式用于获取第一个格式化参数的%控制
            static std::regex fmt_first("^[\\s\\S]*?%[-+ #0]?(\\d+|\\*)?(\\.(?:\\d+|\\*))?(?:hh|h|l|ll|j|z|t|L)?[diuoxXfFeEgGaAcspn]");
            if(std::regex_match(__format,fmt_first)){
                // 实际参数数目与格式化字符串不匹配抛出异常
                throw std::logic_error("invalid format string:missing argument");
            }
            // 调用标准snprintf输出
            return std::snprintf(__stream,__n,__format.c_str());
        }
        template<typename ARG1,typename ...Args>
        static int snprintf (char *__stream, size_t __n, const std::string &__format, ARG1&& first,Args&&...args){
            if(__n<=0)return 0;
            // 正则表达式用于获取第一个格式化参数的%控制
            static std::regex fmt_first("^(?:[^%]|%%)*%[-+ #0]?(\\d+|\\*)?(\\.(?:\\d+|\\*))?(?:hh|h|l|ll|j|z|t|L)?[diuoxXfFeEgGaAcspn]");
            std::smatch m;
            if (!std::regex_search  ( __format, m, fmt_first )){
                // 没有找到%格式控制字符串则抛出异常
                std::cerr<<"extra argument provied to printf\n__format:"<<__format<<std::endl;
                throw std::logic_error("extra argument provied to printf");
            }
            // 调用标准snprintf函数输出第一个参数
            int num=std::snprintf(__stream,__n,m[0].str().c_str(),cvalue(std::forward<ARG1>(first)));
            // 递归调用处理剩余的参数,调整缓冲指针和长度
            return num+snprintf(__stream+num,size_t(__n-num),m.suffix().str(),std::forward<Args>(args)...);
        }
    public:
        // 类printf格式化输出字符串
        template<typename ...Args>
        static std::string format(const std::string &__format,Args&&...args){
            std::vector<char> buffer (size_t(1024));
            int num = snprintf ( buffer.data(), size_t(1024), __format, std::forward<Args>(args)...);
            return std::string(buffer.data(),buffer.data()+num);
        }
    };
}

测试代码:

int main() {
    std::string md5str="b9114c860f2b4bc7698c81a467487174";
    std::string fmt_str=std::string_utils::format(" md5str=%s ######size %d",md5str,md5str.size());
    std::cout<<fmt_str<<std::endl;
}
版权声明:本文为博主原创文章,转载请注明源地址。

相关文章推荐

C++11中的string - to_string/stoi

转自 IBM 编译器中国开发团队的《C++11中的string - atoi/itoa》 在C++11中,由于右值引用的引入,常为人所诟病std::string的性能问题得到了很大的改善。另外一方面...

C++字符串格式化 sprintf、printf

在将各种类型的数据构造成字符串时,sprintf 的强大功能很少会让你失望。由于sprintf 跟printf 在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出...

使用C++11变长参数模板 处理任意长度、类型之参数实例

变长模板、变长参数是依靠C++11新引入的参数包的机制实现的。 一个简单的例子是std::tuple的声明: template class tuple; 这里的三个点“...”表示这个模板参数是...

C 可变长参数 VS C++11 可变长模板

C 可变长参数 VS C++11 可变长模板 分类: C/C++语言2014-07-03 13:50 1088人阅读 评论(0) 收藏 举报 有些时候,我们定义一个函数,可能这个函数需要支持可...

C程序设计语言- 输入与输出-6.1----标准输入与输出、格式化输出(printf)、变长参数表、格式化输入(scanf)、文件访问

前言:继续C系列基础。C系列也快进入尾声了,估计还有俩篇博客。 1.标准输入与输出 2..变长参数表 每一个程序员写的第一个程序大概鼎鼎大名的hello world了,一个简简单单...

java的变长参数

  • 2013-09-29 15:40
  • 20KB
  • 下载

每日一题20:与C++11的第一次邂逅——可变参模板与C#委托模拟

这篇文章本来是前天发的,但是不知道为什么CSDN上没有显示,可能是我没发,记错了。又由于没有留底稿,还是重写一下吧,也为知己不留底稿的恶习做个标记。 之所以接触C++11是因为自己前天突发奇想想用C...

C++11新特性:可变参数模板

C++11新标准增加了可变参数模板,它让我们可以创建可接受可变数量的参数的模板函数和模板类。本文试着较为详尽地介绍可变参数模板函数。首先,C++11提供了一个用省略号表示的元运算符(…),它可以让我们...

C++11中可变参数个数的模板(variadic template)

C++11正式标准是2011年就出来了,前一段时间就听说它增加了不少功能,但一直没用到它。直到最近需要用到可变参数个数的模板,用之前的语法很累赘也存在缺陷,这时查看C++11发现有我需要的类似功能。下...

【Java基础】变长参数、Object[]类别、System.out.println异常

变长参数、Object[]类别和System.out.println异常
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)