template&math
数学一个很重要的概念就是抽象,建立从具体到抽象的总结,与之对应的是有一套成熟的符号演算系统,比如我们用f(x,y)+g(x,f(x,y))这类的东西可以很轻松的表达想要计算的东西…
现代的泛型计算代表了一些来自数学对计算机技术的不满,数学中有完整的理论,比如集合论,泛型分析,比如分析两个空间的同构与否,通过一些等价的代换就可以把复杂的问题最终简化到不证自明的公理层次,可是计算机上呢?总是充满了繁琐的细节…两个体系完全对应不起来
STL引入了一些新鲜的东西,比如 iterator ,实际上是沟通了诸如vector, list, map…这类的桥梁,用数学上来说,这些集合空间都是同构可数的,可以和自然数集合{1,2,3…}对应起来的,所以自然的algorithm可以抛弃具体的集合形态,而是建立在iterator之上…
template引入似乎把一些事情变得有些完美了,可以优雅的实现诸如algorithm::add( x, y) 而又不失效率。但事情真的有那么完美么?
boost的math中vector类库的设计思想还是秉承了STL的一贯做法,为了性能起见,引入了Lazy evaluation,又了Lazy evaluation,vector的operation是通过vector_expression来进行的,实际上是为了达到这样的效果,比如计算 v1 = v2 * 2.0f + v3 ; vector_expression可以保障不用生成太多的中间临时对象,否则传统的做法是 vtmp = v2.operator * ( 2.0f ), v1 = vtmp + v3 ;
看看具体的一段代码,是不是这些模板用的已经有些过分了?
// inner_prod (v1, v2) = sum (v1 [i] * v2 [i])
template
BOOST_UBLAS_INLINE
typename vector_scalar_binary_traits
typename E2::value_type,
typename promote_traits
typename E2::value_type>::promote_type> >::result_type
inner_prod (const vector_expression &e1,
const vector_expression &e2) {
typedef typename vector_scalar_binary_traits
typename E2::value_type,
typename promote_traits
typename E2::value_type>::promote_type> >::expression_type expression_type;
return expression_type (e1 (), e2 ());
}inner_prod (v1, v2) = sum (v1 [i] * v2 [i]) 这是数学给我们的表达式,但上面的实现,仔细看过,你只能说目前的技术也只能做到这一点了,层层的模板typedef就像洋葱头一样,其实本来有更简单的实现,比如用简单的回调函数代替expression_type,实际上最终计算的expression_type就是传统意义上的call back而已,但call back在现代c++中无法做到inline的优化,不然可以做成这样的设计:template
T func_dot_T(T t1, T t2)
{
return (t1 * t2);
};
T func_nop_T(T t1, T t2)
{
return t1;
};
template
class vector_expression
{
public:
typedef typename V::dataType v_type;
typedef v_type (*pFunc)( v_type, v_type );
v_type param;
pFunc func;vector_expression(vector_expression & v_e) {
pV = v_e.pV;
param = v_e.param;
func = v_e.func;
}
vector_expression(V & v, pFunc f, v_type p) {
pV = &v;
func = f;
param = p;
};vector_expression(V & v) {
pV = &v;
func = func_nop_T;
};~vector_expression() {};
return func(pV->operator()(i), param);
}
};
class vectorT
{
T mdata[n];
public:
typedef T dataType;
~vectorT(){};
return mdata[i] ;
};vector_expression operator * ( dataType f )
{
vector_expression v_e(*this, func_dot_T, f);
return v_e;
};
class vector_operation
{
public:
typedef vector_expression v_e;
~vector_operation() {};
v_e v;
int d = v1.dimension();
for(int i=0; i
v.pT->operator () (i) = v1.pT->operator () (i) + v2.pT->operator () (i);
}
return v;
};
};typedef vectorT vec2;vec2 v;
v(0) = 1.0f;
v(1) = 2.0f;vector_expression v_e1 = v * 2.0f ;
float r = v_e1.operator ()(0);
…
实际上这绕来绕去的,只要对编译器做些调整,或者像Qt那样的做个预处理工具,比如实现一个对模板符号的再处理,让这些细节交给工具来作,可以避免写出这些可怕的模板符号出来。