返回信息流想写一个函数,实现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,不知道怎么实现。网上倒是有个这个函数的源码,实在是有点复杂。。。
这是一条镜像帖。来源:北邮人论坛 / cpp / #93853同步于 2016/11/7
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖
函数可变参数
xiaobing307
2016/11/7镜像同步3 回复
订阅后,新回复会通过你的通知中心匿名送达。
3 条回复
带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();
用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好得多。看上去像这样:
: ...................
【 在 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);