boost::preprocessor库的计算替换
来源:互联网 发布:应届生程序员的薪资 编辑:程序博客网 时间:2024/05/16 17:31
上回说到pp库的第一大类功能是关于宏语言计算的支持。今天就来讲讲这个类型的应用。
首先看个例子。打开你的文本编辑器,输入以下内容,并保存为test.cpp
:
#define N 15
#define M (N*(N+1))/2
int m = M;
这段程序用宏设置了一个计算公式:m = (n*(n+1))/2
。我们希望经过预编译,它能输出如下的代码:
int m = 120;
现在我们看看实际情况,执行以下命令:
> g++ -P -E test.cpp > test.out.cpp
-E参数指定g++只进行预编译,而-P选项则禁止预编译器产生一些源代码行号等信息,这样会使的我们的输出结果更加清爽。下面看看执行的结果:
int m = (15*(15+1))/2;
看来,这和我们的预期有差别。
宏语言的所有操作依靠一个概念:expansion,它其实是对一些字符串进行展开的操作,计算并不是它的强 项。在这个例子里,预编译只处理了字符串的替换,而并没有进行数值的计算。当然,这样做,我们程序运行的结果还是没有错的,但区别在于,它把计算放到了运 行时,这样就消耗了运行时的计算资源。而我们则希望,在N值相对固定的时候,尽量利用编译时的资源,而节省运行时的CPU资源。这在大规模的计算时还是有 用处的。
boost::preprocessor
库则为我们提供了宏计算的功能,而不简单地是字符串的替换,下面的代码引入了boost::preprocessor
库:
#include <boost/preprocessor/arithmetic/div.hpp>
#include <boost/preprocessor/arithmetic/mul.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#define N 15
#define M BOOST_PP_DIV( /
BOOST_PP_MUL( N, BOOST_PP_INC(N) ), /
2 )
int m = M;
这里我们用到了三个pp库“函数”:DIV, MUL 和 INC,分别对应整数除,乘和加一操作。输入的时候注意不要遗漏行末的’/'符号,因为我们的宏语句必须是同一行。另一个需要注意的是,每个操作都被包含在一个单一的boost::preprocessor
库的头文件里,而这个头文件的命名是很有规范的,比如我们的宏函数如果是BOOST_PP_ADD,那么它的头文件就在add.hpp
里。这个命名规范也方便我们查阅pp库的在线帮助系统。
插播一下pp库的在线帮助系统。首先从boost.org进入pp库的文档系统,比如目前的1.34.1版本boost的pp库文档位于:
http://boost.org/doc/libs/1_34_1/libs/preprocessor/doc/index.html
在这个页面里,选择左边导航栏的”Reference”,这样就进入了函数查阅页面。这个页面在左边列出了所有的函数名,我们可以非常直观地找到我 们需要查阅的函数,比如查BOOST_PP_ADD的说明,就点击”ADD”条目,这样就进入了该函数的详细说明。养成习惯,尽量使用这个帮助系统,老外 写的文档还是很敬业的:)
好了,同样用g++ -P -E命令对刚才的代码进行预编译,再次查看我们的输出:
int m = 120;
如果你在Windows下测试时,可能会遇到找不到boost库的头文件的问题,请做相应的环境设置,或者简单地用 /I[your boost include dir]
参数来设置。而在linux下,通过诸如ubuntu或者debian这样的包管理安装的boost,所有头文件都按照规范安装到了/usr/include
目录下,我们也就不再为环境设置烦心了。
以上的例子是一个非常简单的用法,你也许会说:我不关心是否占用运行时的CPU资源来进行运算。那么我们下面就结合一下pp库的代码重复生成功能来看看计算的功能。
#include <boost/preprocessor/arithmetic/div.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/arithmetic/dec.hpp>
#include <boost/preprocessor/iteration/local.hpp>
#include <boost/preprocessor/cat.hpp>
#define N 10
typedef struct data
{
#define BOOST_PP_LOCAL_MACRO(n) /
BOOST_PP_CAT( m, n ) ;
#define BOOST_PP_LOCAL_LIMITS (0,N-1)
#include BOOST_PP_LOCAL_ITERATE()
#define MEMBER(m, n) BOOST_PP_CAT( m, n )
void foo(data& input)
{
#define BOOST_PP_LOCAL_MACRO(n) /
MEMBER(m, n) /
= /
MEMBER( input, BOOST_PP_DEC(BOOST_PP_SUB(N,n)) ) ;
#define BOOST_PP_LOCAL_LIMITS (0,N-1)
#include BOOST_PP_LOCAL_ITERATE()
};
};
注意其中的红色部分,这里用计算来计算变量的索引,而这种替换,是绝计无法放到运行时去执行的,否则连C++的编译都通不过。虽然这里涉及到我们还没讲到的代码重复产生功能,但我们可以根据执行这段代码,检查生成的结果来体会宏计算在这里的重要性。
这段代码将产生如下的代码:
typedef struct data
{
m0 ;
m1 ;
m2 ;
m3 ;
m4 ;
m5 ;
m6 ;
m7 ;
m8 ;
m9 ;
void foo(data& input)
{
m0 = input9 ;
m1 = input8 ;
m2 = input7 ;
m3 = input6 ;
m4 = input5 ;
m5 = input4 ;
m6 = input3 ;
m7 = input2 ;
m8 = input1 ;
m9 = input0 ;
};
};
最后,我们需要注意,pp库的计算还是能力很有限的,基本上,它处理不了超过256的计算,比如,我们测试一下以下的代码:
#include <boost/preprocessor/arithmetic/mul.hpp>
#include <boost/preprocessor/arithmetic/div.hpp>
int m = BOOST_PP_MUL( 128, 3 );
int n = BOOST_PP_DIV( 257, 3 );
通过观察结果,乘法的结果是256,显然这是错误的,而除法的结果则是一长窜难于阅读的错误输出,而其实他们都是由于pp库不支持超过256的计 算。而我们的预编译器并不能报出清晰的错误,所有我们一定要对这些限制有所了解,这就要求我们在使用每个pp函数的时候,请一定仔细阅读在线文档里关于该 函数的说明。
- boost::preprocessor库的计算替换
- boost::preprocessor库简介
- boost::preprocessor库使用入门
- boost::preprocessor库之横向重复与纵向重复
- boost::preprocessor库之文件重复与自我重复
- boost::preprocessor库之嵌套循环及其它
- Boost Preprocessor is so cool
- 前端的css preprocessor
- [Boost]_[使用boost库的正则匹配模块替换字符串]
- Boost电路的电感计算
- 用boost的正则替换解决问题
- 使用boost库来计算文件夹的大小
- Cpp的预处理Preprocessor-笔记
- jmeter BeanShell PreProcessor的用法
- Boost-Boost库的编译
- Java 单文本替换并计算替换的个数
- VS2013 里的Preprocessor definitions 有bug
- PReprocessor Macros : 全局宏命令的应用
- ASP.NET2.0 学习笔记(一)
- 芒果有时说再见
- 雷柏7100使用一周有感——优缺点
- 某人整理的游戏编程资料
- VMware下Linux的安装及简单设置
- boost::preprocessor库的计算替换
- 《纳税富翁》惊现漏洞,一步不走也赚五千万
- 经典语录--余世维
- 胡立阳--安之机构炒股演讲
- svn update时如何不自动合并文件
- Jive学习_1
- Scott Mitchell 的ASP.NET 2.0数据教程之七:使用DropDownList过滤的主/从报表
- 网站登录搜索引擎入口
- Scott Mitchell 的ASP.NET 2.0数据教程之六::设置ObjectDataSource的参数值