BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / cpp / #93853同步于 2016/11/7
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖

函数可变参数

xiaobing307
2016/11/7镜像同步3 回复
想写一个函数,实现string类追加格式化字符串。 原型如下: void StringAppendF(std::string* dst, const char* format, ...); 用法: const char* name = "zhangsan"; int age = 20; std::string s; StringAppendF(&s, "%s\t%d\n", name, age); cout << s << endl; 不知道有没有简单一点的方法来实现? 比如函数里面调个sprintf,不知道怎么实现。网上倒是有个这个函数的源码,实在是有点复杂。。。
订阅后,新回复会通过你的通知中心匿名送达。
3 条回复
nuanyangyang机器人#1 · 2016/11/7
带varargs的函数都不太容易实现。尽管用起来很爽。毕竟调用方按照C/C++的系统标准的calling convention把参数放到相应寄存器里,但被调方就麻烦了。一方面被调方不知道调用方传来了几个参数,所以只能通过那个format字符串估测后面参数的个数,猜对了没问题,猜错了机器就冒烟了。 C++11有variadic template,看上去不错:http://en.cppreference.com/w/cpp/language/parameter_pack 还可以递归应用模板:http://nerdparadise.com/forum/openmic/5712/ 另外,C++的String API让人很想吐槽。要不要试试Qt的QString呢?国际化比std::string好得多。看上去像这样: MyString msg_chinese = MyStringBuilder("学{0}技术,去{1}学校").arg(0, skill).arg(1, school).to_string(); MyString msg_english = MyStringBuilder("Go to the {1} academy to learn the {0} technique.").arg(0, skill).arg(1, school).to_string();
xiaobing307机器人#2 · 2016/11/7
用qt,小用一下还得装个库,太麻烦。看来只好不封装函数,用snprintf,再追加到string了。 ps:string类接口的槽点在哪? 【 在 nuanyangyang 的大作中提到: 】 : 带varargs的函数都不太容易实现。尽管用起来很爽。毕竟调用方按照C/C++的系统标准的calling convention把参数放到相应寄存器里,但被调方就麻烦了。一方面被调方不知道调用方传来了几个参数,所以只能通过那个format字符串估测后面参数的个数,猜对了没问题,猜错了机器就冒烟了。 : C++11有variadic template,看上去不错:http://en.cppreference.com/w/cpp/language/parameter_pack 还可以递归应用模板:http://nerdparadise.com/forum/openmic/5712/ : 另外,C++的String API让人很想吐槽。要不要试试Qt的QString呢?国际化比std::string好得多。看上去像这样: : ...................
nuanyangyang机器人#3 · 2016/11/7
【 在 xiaobing307 的大作中提到: 】 : 用qt,小用一下还得装个库,太麻烦。看来只好不封装函数,用snprintf,再追加到string了。 : ps:string类接口的槽点在哪? 第一点,string和iostream完全没有“格式化”的意思。比如cout<<"学汽车,去"<<blueshit.name()<<"驾校"<<endl; ,完全是顺序结构,完全没有“格式化”的意思。“格式化”的要点就是可以灵活地指定格式,比如"The value is %.02lf percent\n",指定类型,以及小数、小数位数。Python的话,语法不一样但是原则是一样的:"The value is {:.02f} percent"。这样的模式一目了然。反观C++的iostream的iomanip用起来非常麻烦: cout << "The value is " << setprecision(2) << value << "percent" << endl; 更何况setprecision是一种副作用,影响下一次输出数值,下一次还要重新设回来。而不管是C的printf还是Python的format,这一次格式化对下一次格式化都是无副作用的。 第二点,国际化。不同的语言,语序是不同的。所以,凡是考虑到国际化的模板系统,都会允许在模式里指定参数的顺序。比如 english = { template: "Go to {1} to learn {0}", skill: "excavator", school: "blue shit", } chinese = { template: "学{0},去{1}", skill: "挖掘机", school: "蓝翔", } for lang in [english, chinese]: print(lang.template.format(lang.skill, lang.school)) 不仅仅Python支持,Java的MessageFormat也支持(Java1.1就有了哦): String msgEng = MessageFormat.format("Go to {1} to learn {0}", "excavator", "blue shit"); String msgChs = MessageFormat.format("学{0}去{1}", "挖掘机", "蓝翔"); Qt的QString也是一样: QString eng = QString("Go to %2 to learn %1").args("excavator", "blue shit"); QString chs = QString("学%1去%2").args("挖掘机", "蓝翔"); C++还有一个专门的fmtlab,也支持这种格式化方法: https://github.com/fmtlib/fmt std::string eng = fmt::format("Go to {1} to learn {0}", "excavator", "blue shit"); std::string chs = fmt::format("学{0}去{1}", "挖掘机", "蓝翔"); 而且竟然还有个FMT_VARIADIC宏,看上去就是你想要的: // You can use the FMT_VARIADIC macro to create your own functions similar to format and print which take arbitrary arguments: // Prints formatted error message. void report_error(const char *format, fmt::ArgList args) { fmt::print("Error: "); fmt::print(format, args); } FMT_VARIADIC(void, report_error, const char *) report_error("file not found: {}", path);