初见boost的名字参数,给人一种“惊为天人”的感觉,没想到在c++中还能写出如此优雅的令人震撼的代码。boost的名字参数采用的是C++的范型来实现的,全部在编译期完成名字到参数的定位,没有RTTI,没有运行时开销,不需要任何元数据。她依旧沿袭了C++的高效原则,带来的缺点就是无法跨二进制代码使用。当然boost的名字参数不是拿出来炫耀C++的强大能力的,要看c++编译期的强大能力,boost.MPL才能让人忍不住挺身呐喊。她的主要目的是简化graph library的复杂的函数差数调用.动则数十个参数的函数调用,必须遵循严格的调用顺序让人头痛不已(还让人活吗?要么自己写一套算法?!),名字参数就像一个天使来到人间,她是如此的优雅,迷人,让人心醉(不要流口水!),从此,有了她的C++程序员都过上了幸福的生活!
假设有下面的函数
void fun(T1 t1,T2 t2,T3* t3=0,.. ,T20* t20=0);
其中后十个参数是可选的,如果你想给t20传入一个非缺省值,那么看起来你要给所有的函数参数赋值才能通过编译了。肯定没人愚蠢到用排列组合的方式来添加N个函数给用户使用吧。怎么办呢?想不出来,不要紧,假设boost.graph有这样一个类似的函数,我们先看看她是如何调用这个函数的,关键是学到的东西要能发挥作用,给人以良好的感觉
fun(t1,t2,Param<T20*>
(&T20()));
当然,这只是一个看起来和她机制一样的而又较简单,容易理解的方式。够简单吧,不要惊讶,其实说起来,她的原理还是很简单的,只是要自己实作一个作品还是有点难度。为了实现boost.graph,专门做了一个相对简单的property map库,在她的基础上建立了针对boost.graph名字参数系统,其实这一套机制可以用在更宽泛的库中,不知道为什么没有放出来。boost.graph的实作看起来令人生畏:visitor,named_param,class_generator,Python bindings,她的每种技术都可以让人够研究好一段时间。我们就用简单的例子来说明名字参数的原理,不是严格按她的类来组织的。
先看同名成员变量是如何访问的。
struct B
{
string val;
};
struct D:B
{
int val;
};
看下面的访问函数
D d; d.val=100;//OK D::val=100
d.val="10";//error D::val (int) can't assign with a string
//but we can access it by
((B).d).val="10";
如果我们能绕过这个问题,问题就完成了一大半了,其实方法很简单。即使给每个参数加个名字,有了名字以后,我们就可以找到对应的项,也不会有类型冲突的问题发生。
struct no_param{};
struct B:no_param
{
typename name_B name;
string val;
};
template<class B>
struct D:B
{
typedef B base;
typename name_D name;
int val;
};
//假设下面的模版会传入<D,name_B>
template<typename propertys,typename tag>
struct select
{
typedef if_else< //select second type if first return true,else third
if_same<property::name,tag>::value, // D::name!=name_B ,false
property, //
select<property::base,tag>::type> //recurive call select,will pass <B,name_B>,this call will success return B
>::type type; //get the third type,it return B,so type is defined as B
}
这样一来,我们就可以根据名字访问B的变量val了
((select::type)(d)).val="success";
虽然boost.graph的名字系统比这个复杂多了,但万变不离其宗,其原理是一样的。如此奇妙的东西竟然建立在如此简单的机制上,可见只有想不到的东西,没有做不到的东西这句话还是有一定道理的,更印证了那句"简单就是美"的名言.
下次继续分析boost.graph的visitor机制.
//if_same and if_else
template<class T1,class T2>
struct if_same
{
enum{value=false};
};
template<class T>
struct if_same<T,T>
{
enum{value=true};
}
template<bool value,class T1,class T2>
struct if_else
{
typedef T1 type;
}
template<class T1,class T2>
struct if_else<false,T1,T2>
{
typedef T2 type;
}