因为boost::format库使用类似stringstream类来进行格式化,所以不需要指定参数的类型,例如%d, %f, %c等,直接指定参数位置就可以了。
可以实现类似python的字符串格式化效果。
对于格式化字符 %本身,可以使用两个 %%来进行转义。
程序代码如下,
CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
project(lexical_cast)
add_definitions(-std=c++14)
include_directories("/usr/local/include")
link_directories("/usr/local/lib")
file( GLOB APP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
foreach( sourcefile ${APP_SOURCES} )
file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${sourcefile})
string(REPLACE ".cpp" "" file ${filename})
add_executable(${file} ${sourcefile})
target_link_libraries(${file} boost_filesystem boost_thread boost_system boost_serialization pthread boost_chrono)
endforeach( sourcefile ${APP_SOURCES} )
main.cpp
#include
// 注意转义字符 %% 表示 一个 %的用法
#include
class i_hold_some_internals {
int i;
std::string s;
char c;
public:
i_hold_some_internals():
i(100),
s("Reader"),
c('!')
{}
// 格式化参数必须包含下面的字符
// %1% i
// %2% s
// %3% c
std::string to_string(const std::string& format_specifier) const {
boost::format f(format_specifier);
// 去掉too_many_args_bit位,保留其他位
unsigned char flags = boost::io::all_error_bits;
flags ^= boost::io::too_many_args_bit;
f.exceptions(flags);
return (f % i % s % c).str();
}
};
int main(int argc, char* argv[]) {
i_hold_some_internals class_instance;
std::cout << class_instance.to_string(
"Hello, dear %2%! "
"Did you read the book for %1% %% %3%\n");
std::cout << class_instance.to_string(
"%1% == %1% && %1% %% != %1%\n\n"
);
// 输出 "Reader"
std::cout << class_instance.to_string("%2%\n\n");
try {
class_instance.to_string("%1% %2% %3% %4% %5%\n");
} catch(const std::exception& e) {
std::cerr << e.what() << '\n';
}
}
程序输出如下,
原理解析,请看下图,
我们看下basic_format类的一些参数定义,
每一个格式化选项被抽象成了一个item对象, std::vector
std::vector
int cur_arg_;是当前处理的arg数,从0开始。 还是上面的例子,如果现在是 %3,那么 int cur_arg=2。
int num_args_; 总共的格式化参数个数,如果是上面的例子, int num_args_=5。
mutable bool dumped_; 是否已经调用过 str()方法,如果调用过,说明已经格式化过一次了。重新格式化的话,要清空重来。
string_type prefix_; 第一个格式化元素之前需要插入的前缀。
详细的代码可以自己去看,完全和我的解释项应证。
所以这里还需要理解的一个东西就是 每一个格式化元素被映射成了一个格式化选项format_item_t,format_item_t是个什么东西?
看一下format_item_t的一个成员列表
argN,当前处理到的参数号。从0开始,和basic_format中的cur_arg相对应。
string_type res; 当前 格式化字符替换后的结果,例如 %1%需要被替换成100,这里的res就是std::string res = "100"。
string_type appendix_; 当前格式化字符和下一个格式化字符之间的字符串。
其他的成员就没那么重要了。
我们再来看basic_format类的 % 号操作符重载 operator%(const T& x)。
直接跳到feed_impl方法
feed_impl方法又调用了一个distribute方法,
distribute方法的上半部分反映了最前面代码中设置异常标志位的意义,只有对应异常的异常标志位为1,才会抛出相应的异常。
下面一部分的put方法,意图就比较明显了,使用buf_做缓冲区,把x中的内容填充到当前item的res字段中。
这样逐个 格式化选项处理完毕之后,
basic_format类的items_字段中就包含了所有格式化所需要的信息。
我们接着看 basic_format::str()方法
str方法就是简单的把items_中的内容拼接起来,然后返回一个std::string。
最后把dumped字段设置为true,表示之前已经格式化过一次了。