我想创建一个带有嵌入信息的字符串。 实现我想要的目标的一种方法(不是唯一的方法)叫做字符串插值或变量替换,其中字符串中的占位符被替换为实际值。
在C语言中,我会这样做:
printf("error! value was %d but I expected %d",actualValue,expectedValue)
而如果我是用python编程,我会做这样的事情:
"error! value was {0} but I expected {1}".format(actualValue,expectedValue)
这两个例子都是字符串插值。
我如何在C++中做到这一点?
重要注意事项:
std::cout
:cout << "error! value was " << actualValue << " but I expected "
<< expectedValue;
我不想将字符串打印到stdout。 我想将一个std::string
作为参数传递给一个函数(例如异常对象的构造函数)。
编辑
对于我的直接用法,我不关心性能(我正在为crying‘out loud引发一个异常!)。 然而,了解各种方法的相对性能通常非常非常有用。
为什么不直接使用printf本身(C++毕竟是C的超集……)呢? 这个答案讨论了一些为什么不这样做的原因。 据我所知,类型安全是一个很大的原因:如果您放入%d,那么您放入的变量最好是可以转换为整数的,因为函数就是这样计算出它是什么类型的。 使用要插入的变量的实际类型的编译时知识的方法要安全得多。
方法1:使用字符串流
看起来std::stringstream
提供了一个快速解决方案:
std::stringstream ss;
ss << "error! value was " << actualValue << " but I expected " << expectedValue << endl;
//example usage
throw MyException(ss.str())
阳性
阴性
方法二:Boost格式
Boost格式库也是一种可能。 使用它,您可以做到:
throw MyException(boost::format("error! value was %1% but I expected %2%") % actualValue % expectedValue);
阳性
阴性
编辑:
方法3:可变模板参数
printf的类型安全版本似乎可以通过使用可变模板参数(用于模板参数数目不定的技术术语)来创建。 我在这方面看到了一些可能性:
阳性
阴性
在C++20中,您将能够使用std::formater
。
已接受的论文见http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2019/p0645r9.html。
这将支持python样式的格式设置:
string s1 = std::format("{1} to {0}", "a", "b");
已经有一个可用的实现:https://github.com/fmtlib/fmt
在C++11中,您可以使用std::to_string
:
"error! value was " + std::to_string(actualValue) + " but I expected " + std::to_string(expectedValue)
它并不漂亮,但很简单,你可以用一个宏来缩小它。 性能不是很好,因为您事先没有保留()
空间。 可变模板可能会更快,看起来更好。
这种字符串构造(而不是插值)也不利于本地化,但如果需要,您可能会使用库。