C++ Boost Format超详细讲解
无水先生 人气:0Boost.Format 提供了函数 std::printf() 的替代品。 std::printf() 源自 C 标准并允许格式化数据输出。但是,它既不是类型安全的,也不是可扩展的。 Boost.Format 提供了一种类型安全且可扩展的替代方案。
Boost.Format 提供了一个名为 boost::format 的类,该类在 boost/format.hpp 中定义。与 std::printf() 类似,将包含用于控制格式的特殊字符的字符串传递给 boost::format 的构造函数。替换输出中这些特殊字符的数据通过运算符 operator% 链接。
示例 7.1。使用 boost::format 格式化输出
#include <boost/format.hpp> #include <iostream> int main() { std::cout << boost::format{"%1%.%2%.%3%"} % 12 % 5 % 2014 << '\n'; }
Boost.Format 格式字符串使用放置在两个百分号之间的数字作为实际数据的占位符,这些数据将使用 operator% 进行链接。示例 7.1 使用数字 12、5 和 2014 作为数据创建格式为 12.5.2014 的日期字符串。为了使月份出现在日期的前面,这在美国很常见,可以交换占位符。示例 7.2 进行了此更改,显示 2014 年 5 月 12 日
示例 7.2。带有 boost::format 的编号占位符
#include <boost/format.hpp> #include <iostream> int main() { std::cout << boost::format{"%2%/%1%/%3%"} % 12 % 5 % 2014 << '\n'; }
为了使用操纵器格式化数据,Boost.Format 提供了一个名为 boost::io::group() 的函数。
示例 7.3。使用带有 boost::io::group() 的操纵器
#include <boost/format.hpp> #include <iostream> int main() { std::cout << boost::format{"%1% %2% %1%"} % boost::io::group(std::showpos, 1) % 2 << '\n'; }
示例 7.3 对将与“%1%”关联的值使用操纵器 std::showpos()。因此,此示例将显示 +1 2 +1 作为输出。因为操纵器 std::showpos() 已使用 boost::io::group() 链接到第一个数据值,所以只要显示该值,就会自动添加加号。在这种情况下,格式占位符“%1%”会使用两次。
如果加号仅应显示为 1 的第一个输出,则需要自定义格式占位符。
示例 7.4。带有特殊字符的占位符
#include <boost/format.hpp> #include <iostream> int main() { std::cout << boost::format{"%|1$+| %2% %1%"} % 1 % 2 << '\n'; }
示例 7.4 就是这样做的。在此示例中,占位符“%1%”的第一个实例被替换为“%|1$+|”。格式的定制不仅仅是添加两个额外的管道符号。对数据的引用也放在管道符号之间,并使用“1$”而不是“1%”。这是将输出修改为 +1 2 1 所必需的。您可以在 Boost 文档中找到有关格式规范的详细信息。 必须为所有占位符或不指定对数据的占位符引用。示例 7.5 仅提供三个占位符之一的引用,这会在运行时生成错误。
示例 7.5。 boost::io::format_error 以防出错
#include <boost/format.hpp> #include <iostream> int main() { try { std::cout << boost::format{"%|+| %2% %1%"} % 1 % 2 << '\n'; } catch (boost::io::format_error &ex) { std::cout << ex.what() << '\n'; } }
示例 7.5 引发了 boost::io::format_error 类型的异常。严格来说,Boost.Format 会抛出 boost::io::bad_format_string。但是,由于不同的异常类都是从 boost::io::format_error 派生的,因此通常更容易捕获这种类型的异常。
示例 7.6 展示了如何在不使用格式字符串中的引用的情况下编写程序。
示例 7.6。没有数字的占位符
#include <boost/format.hpp> #include <iostream> int main() { std::cout << boost::format{"%|+| %|| %||"} % 1 % 2 % 1 << '\n'; }
在这种情况下,可以安全地省略第二个和第三个占位符的管道符号,因为它们没有指定任何格式。生成的语法与 std::printf() 非常相似(参见示例 7.7)。
示例 7.7。 boost::format 使用来自 std::printf() 的语法
#include <boost/format.hpp> #include <iostream> int main() { std::cout << boost::format{"%+d %d %d"} % 1 % 2 % 1 << '\n'; }
虽然格式可能看起来像 std::printf() 使用的格式,但 Boost.Format 提供了类型安全的优势。格式字符串中的字母“d”不表示数字的输出。相反,它将操纵器 std::dec() 应用于 boost::format 使用的内部流对象。这使得指定对 std::printf() 没有意义的格式字符串成为可能,并且会导致崩溃。
示例 7.8。 boost::format 带有看似无效的占位符
#include <boost/format.hpp> #include <iostream> int main() { std::cout << boost::format{"%+s %s %s"} % 1 % 2 % 1 << '\n'; }
std::printf() 只允许 const char* 类型的字符串使用字母“s”。使用 std::printf() 时,“%s”和数值的组合会失败。但是,示例 7.8 完美运行。 Boost.Format 不需要字符串。相反,它应用适当的操纵器来配置内部流。
Boost.Format 既是类型安全的又是可扩展的。只要运算符 operator<< 为 std::ostream 重载,任何类型的对象都可以与 Boost.Format 一起使用。
示例 7.9。 boost::format 具有用户定义的类型
#include <boost/format.hpp> #include <string> #include <iostream> struct animal { std::string name; int legs; }; std::ostream &operator<<(std::ostream &os, const animal &a) { return os << a.name << ',' << a.legs; } int main() { animal a{"cat", 4}; std::cout << boost::format{"%1%"} % a << '\n'; }
示例 7.9 使用 boost::format 将用户定义类型动物的对象写入标准输出。这是可能的,因为流运算符对于动物来说是重载的。
加载全部内容