表达式模板expression template
来源:互联网 发布:淘宝后台填写宝贝 编辑:程序博客网 时间:2024/06/01 09:18
原创作品,转载请注明版权信息。
这篇文章我们将学习如何把上篇文章中提高性能采用的Lazy Evaluation的技术推广到更加广义的应用。
相关代码请参阅:
http://en.wikipedia.org/wiki/Expression_templates
这部分代码对初学者是有一定的难度。我们一个一个类来学习提高:
第一个类:
template <typename E>
// A CRTP base class for Vecs with a size and indexing:
class VecExpression
{
public:
typedef std::vector<double> container_type;
typedef container_type::size_type size_type;
typedef container_type::value_type value_type;
typedef container_type::reference reference;
//get the size
size_type size() const { return static_cast<E const&>(*this).size(); }
//access the element using []
value_type operator[](size_type i) const { return static_cast<E const&>(*this)[i]; }
//function call operator(), const variation for other type applications
operator E&() { return static_cast<E&>(*this); } //
operator E const&() const { return static_cast<const E&>(*this); }
};
container_type为标准库的vector<double>,也就是说现在要处理vector类型的表达式问题。
成员函数:
size(): 我们调用的是E类型的size(), 因此在此作了一个强制类型转换。
operator E&(): 这定义了一个隐式的类型转换。这种定义类似于构造函数,没有返回类型,把当前的VecExpression类型转化为E&类型。这样当表达式中要把VecExpression(或者其派生类类型)转化为E类型(非常量),这个函数就被调用。
operator E const&() 同上,在需要常量类型时调用。
看来,这个类型主要是为了一个到类型E的转换中介。
第二个类:
// The actual Vec class:
class Vec : public VecExpression<Vec>
{
container_type _data; //stl vector type
public:
//access vector elements
reference operator[](size_type i) { return _data[i]; }
value_type operator[](size_type i) const { return _data[i]; }
//access vector size
size_type size() const { return _data.size(); }
//constructor
Vec(size_type n) : _data(n) {} // Construct a given size:
// Construct from any VecExpression:
template <typename E>
Vec(VecExpression<E> const& vec)
{
E const& v = vec;
_data.resize(v.size());//clear and resize, why we need this???it is already allocated
for (size_type i = 0; i != v.size(); ++i)
{
_data[i] = v[i];
}
}
template <typename E>
//Vec(VecExpression<E> const& vec)
Vec& operator=(VecExpression<E> const& vec)
{
E const& v = vec;
//_data.resize(v.size());//clear and resize, why we need this???it is already allocated
for (size_type i = 0; i != v.size(); ++i)
{
_data[i] = v[i];
}
return (*this);
}
};
类型Vec继承上面的VecExpression,同时具体化类未知类型E类型Vec,也就是说,上面的隐式类型转换要转换到Vec类型。
1。定义了一个std::vector<double>的成员对象,也就是这个是我们要处理的数据。
2。operator[] 用于存取Vec对象里的元素。为什么需要两个?reference_type返回引用,可以用于左边或右边,value_type返回的值,只能用于右边。现在我还不清楚为什么需要这个值类型。
3。构造函数Vec(size_type n)调用std::vector的构造函数用于分配给定长度的向量空间。
4。复制构造函数。注意它是用一个VecExpression<E>类型来构造Vec类型。这个好像有点难以理解。其表达的其实正是我们问题的核心:把一个向量表达式类型构造一个向量,比如:Vec c=a+b; (a,b 均为Vec类型,a*b为VecExpression<Vec>类型,也就是向量表达式类型。
5。赋值运算符,这个运算符是我加的,为的是支持Vec c; c=a+b; 这种表达式。
第三个类:
//vector addition
template <typename E1, typename E2>
class VecAdd : public VecExpression<VecAdd<E1, E2> >
{
E1 const& _u;
E2 const& _v;
public:
typedef Vec::size_type size_type;
typedef Vec::value_type value_type;
VecAdd(VecExpression<E1> const& u, VecExpression<E2> const& v) : _u(u), _v(v) {
assert(u.size() == v.size());
}
size_type size() const { return _v.size(); }
value_type operator[](Vec::size_type i) const { return _u[i] + _v[i]; }
};
这个类用于实现两个向量的加法。(一种具体的向量表达式类型)。我们可以清楚地看到,这个类就是上一篇文章里的延迟求值。
a+b被定义为保存了a和b的引用,构造了一个VecAdd类型的对象。
显然我们还需要定义一个operator+,以连接起VecAdd:
template <typename E1, typename E2>
VecAdd<E1,E2> const
operator+(VecExpression<E1> const& u, VecExpression<E2> const& v)
{
return VecAdd<E1,E2>(u,v);
}
operator[] 实现了对两个向量对应元素相加。
我们看到,当遇到表达式:
Vec a,b;
Vec c=a+b;
首先,a和b均为Vec类型,调用上面的operator+函数(注意形参里使用的是基类类型,因此要用到类型转换!),构造一个VecAdd类型的对象。
当遇到Vec c=VecAdd(),这样一个表达式时,调用构造函数,对每一个成员进行复制,这时候又要调用VecAdd的元素存取运算符operator[],在此时完成了向量的加法。
为方便起见,我把一个完整的实现与测试程序贴在这儿供大家练习,加入其他的运算都是很直接了当的:
#include <vector>
#include <cassert>
#include "windows.h"
#include <iostream>
#pragma optimize("",on)
class hptime
{
LARGE_INTEGER sys_freq;
public:
hptime(){QueryPerformanceFrequency(&sys_freq);}
double gettime()
{
LARGE_INTEGER tick;
QueryPerformanceCounter(&tick);
return (double)tick.QuadPart*1000.0/sys_freq.QuadPart;
}
};
//from: http://en.wikipedia.org/wiki/Expression_templates
template <typename E>
// A CRTP base class for Vecs with a size and indexing:
class VecExpression
{
public:
typedef std::vector<double> container_type;
typedef container_type::size_type size_type;
typedef container_type::value_type value_type;
typedef container_type::reference reference;
//get the size
size_type size() const { return static_cast<E const&>(*this).size(); }
//access the element using []
value_type operator[](size_type i) const { return static_cast<E const&>(*this)[i]; }
//function call operator(), const variation for other type applications
operator E&() { return static_cast<E&>(*this); } //
operator E const&() const { return static_cast<const E&>(*this); }
};
// The actual Vec class:
class Vec : public VecExpression<Vec>
{
container_type _data; //stl vector type
public:
//access vector elements
reference operator[](size_type i) { return _data[i]; }
value_type operator[](size_type i) const { return _data[i]; }
//access vector size
size_type size() const { return _data.size(); }
//constructor
Vec(size_type n) : _data(n) {} // Construct a given size:
// Construct from any VecExpression:
template <typename E>
Vec(VecExpression<E> const& vec)
{
E const& v = vec;
_data.resize(v.size());//clear and resize, why we need this???it is already allocated
for (size_type i = 0; i != v.size(); ++i)
{
_data[i] = v[i];
}
}
template <typename E>
//Vec(VecExpression<E> const& vec)
Vec& operator=(VecExpression<E> const& vec)
{
E const& v = vec;
//_data.resize(v.size());//clear and resize, why we need this???it is already allocated
for (size_type i = 0; i != v.size(); ++i)
{
_data[i] = v[i];
}
return (*this);
}
};
//vector addition
template <typename E1, typename E2>
class VecAdd : public VecExpression<VecAdd<E1, E2> >
{
E1 const& _u;
E2 const& _v;
public:
typedef Vec::size_type size_type;
typedef Vec::value_type value_type;
VecAdd(VecExpression<E1> const& u, VecExpression<E2> const& v) : _u(u), _v(v) {
assert(u.size() == v.size());
}
size_type size() const { return _v.size(); }
value_type operator[](Vec::size_type i) const { return _u[i] + _v[i]; }
};
// Now we can overload operators:
template <typename E1, typename E2>
VecAdd<E1,E2> const
operator+(VecExpression<E1> const& u, VecExpression<E2> const& v)
{
return VecAdd<E1,E2>(u,v);
}
#include <iostream>
using namespace std;
int main()
{
hptime t0;
const int n=1000000;
int i,j,k;
double dtime;
double *v10,*v20,*v30;
Vec v1(n),v2(n),v3(n);
v10=&v1[0];
v20=&v2[0];
v30=&v3[0];
for(i=0;i<n;i++)
{
v1[i]=i;
v2[i]=i*1.1;
}
dtime=t0.gettime();
v3=v2+v1; //call operator=
dtime=t0.gettime()-dtime;
cout<<"Expression template: "<<dtime<<" ms\n";
//compare with direct double calculation
dtime=t0.gettime();
for(i=0;i<n;i++)
v30[i]=v20[i]+v10[i];
dtime=t0.gettime()-dtime;
cout<<"Vector element: "<<dtime<<" ms\n";
}
- 表达式模板expression template
- expression template 表达式模板
- Expression Template(表达式模板,ET)
- Expression Template(表达式模板,ET)
- 奇异递归模板模式(CRTP)应用--表达式模板(expression template) 2
- 表达式模板(expression templates)
- 表达式模板 expression templates 测试
- Expression Blend实例中文教程(12) - 样式和模板快速入门Style,Template
- Expression Blend实例中文教程(12) - 样式和模板快速入门Style,Template
- Expression Blend实例中文教程(12) - 样式和模板快速入门Style,Template
- Expression Blend实例中文教程(12) - 样式和模板快速入门Style,Template
- 模板Template
- 模板Template
- 模板(template)
- template 模板
- 模板template
- 模板(Template)
- template模板
- 复制图纸空间的视口到另一个dwg文件中2(wblockcloneobjects方法)
- Session学习笔记
- PowerPC E300处理器核超详细介绍
- 从角色的角度理解工厂方法模式和抽象工厂模式
- hdu 1513 使用滚动数组的最长公共子序列
- 表达式模板expression template
- 常见互联网技术地址汇总
- 链式结构的队(练习)
- Mixer编程
- C#启动窗体的制作—基于线程技术实现
- 外设位宽为8、16、32时,CPU与外设之间地址线的连接方法
- android中使用GestureDetector.OnGestureListener对触屏事件进行分析的使用后感
- C/C++/C#/Java程序员的Ruby第二天
- 深入分析存储器的位宽及与C的关系