`
jgsj
  • 浏览: 960262 次
文章分类
社区版块
存档分类
最新评论

模板元编程在立体几何中的妙用

 
阅读更多
<style type="text/css"> <!-- @page {margin:2cm} pre {font-family:"DejaVu Sans Mono",monospace} p.我的格式-western {font-family:"DejaVu Sans",sans-serif; font-size:10pt} p.我的格式-cjk {font-size:10pt} p.我的格式-ctl {font-size:12pt} p {margin-bottom:0.21cm} --> </style>

模板元编程在立体几何中的妙用

为了更好地理解三维游戏编程,我开始研究了立体几何,注意,是立体解析几何,里面涉及到了很多元组、向量和矩阵的知识。虽然还有一些不懂,可是这唤醒了我在高等数学中学到的知识,我想以后还是有很大的用处的。

当然,数学是工具,是为我们编程服务的。但是出于对性能和简洁性的敏感,在构建数学库的过程中我千方百计减少我们的代码量。在我所学的封装、继承和多态以及模板中进行选择,最后我尝试了一下模板。

我学习了一下模板,发现这是一个非常好的特性。使用模板偏特化的技术,可以让编译器在编译器为我们做一些事情。我们先了解一下,这是在博客园中salomon的一篇介绍模板元编程中的例子,没错,就是求菲波那锲数列的和。

// 主模板
template<int N>
struct Fib
{
    enum { Result = Fib<N-1>::Result + Fib<N-2>::Result };
};
// 完全特化版
template <>
struct Fib<1>
{
    enum { Result = 1 };
};
// 完全特化版
template <>
struct Fib<0>
{
    enum { Result = 0 };
};
int main()
{
    int i = Fib<10>::Result;
    // std::cout << i << std::endl;
}

从这里可以看出,主模板带的参数是一个整型的数,而不是typename,得益于这一点,C++才有模板元编程,而其它高级语言只有泛型编程。

这里我有一个需求。在3D游戏编程中,常常需要二维、三维、四维的矢量,以便各种各样的数学运算。比方说需要求出两个向量确定平面的法向量,这一点在微软D3D中的d3dx9math.h中有很多体现,此外还需要适配基本的格式,像OpenGL一样,既提供float型的也提供double型的。

怎么实现呢?的确,用模板很好实现:

#ifndef MATH3D_H
#define MATH3D_H
// 以下代码需要高级版本C++编译器支持
template <typename T, int n>
union Tuple
{
    T m[n];
};
// 特化
template <typename T>
union Tuple<T, 2>
{
    Tuple( void ){ }
    Tuple( T _1, T _2 )
    {
        Set( _1, _2 );
    }
    void Set( T _1, T _2 )
    {
        m[0] = _1, m[1] = _2;
    }
    operator T*( void ) // 重载类型转换函数
    {
        return m;
    }
    Tuple operator+( const Tuple& obj ) const// 重载减号
    {
        Tuple ret;
        ret.m[0] = m[0] + obj.m[0];
        ret.m[1] = m[1] + obj.m[1];
        return ret;
    }
    Tuple operator-( const Tuple& obj ) const// 重载减号
    {
        Tuple ret;
        ret.m[0] = m[0] - obj.m[0];
        ret.m[1] = m[1] - obj.m[1];
        return ret;
    }
    Tuple& operator+=( const Tuple& obj )
    {
        m[0] += obj.m[0];
        m[1] += obj.m[1];
        return *this;
    }
    //-------------------------------------
    T m[2];
    struct
    {
        T x, y;
    };
    struct
    {
        T w, h;
    };
};
template <typename T>
union Tuple<T, 3>
{
    Tuple( void ){ }
    Tuple( T _1, T _2, T _3 )
    {
        Set( _1, _2, _3 );
    }
    void Set( T _1, T _2, T _3 )
    {
        m[0] = _1, m[1] = _2, m[2] = _3;
    }
    operator T*( void ) // 重载类型转换函数
    {
        return m;
    }
    Tuple operator+( const Tuple& obj ) const// 重载减号
    {
        Tuple ret;
        ret.m[0] = m[0] + obj.m[0];
        ret.m[1] = m[1] + obj.m[1];
        ret.m[2] = m[2] + obj.m[2];
        return ret;
    }
    Tuple operator-( const Tuple& obj ) const// 重载减号
    {
        Tuple ret;
        ret.m[0] = m[0] - obj.m[0];
        ret.m[1] = m[1] - obj.m[1];
        ret.m[2] = m[2] - obj.m[2];
        return ret;
    }
    Tuple operator*( const T& obj )     const// 重载减号
    {
        Tuple ret;
        ret.m[0] = m[0] * obj;
        ret.m[1] = m[1] * obj;
        ret.m[2] = m[2] * obj;
        return ret;
    }
    Tuple operator-( void )
    {
        return Tuple( -m[0], -m[1], -m[2] );
    }
    Tuple& operator+=( const Tuple& obj )
    {
        m[0] += obj.m[0];
        m[1] += obj.m[1];
        m[2] += obj.m[2];
        return *this;
    }
    //-------------------------------------
    T m[3];
    struct
    {
        T x, y, z;
    };
    struct
    {
        T r, g, b;
    };
};
template <typename T>
union Tuple<T, 4>
{
    Tuple( void ){ }
    Tuple( T _1, T _2, T _3, T _4 )
    {
        Set( _1, _2, _3, _4 );
    }
    void Set( T _1, T _2, T _3, T _4 )
    {
        m[0] = _1, m[1] = _2, m[2] = _3, m[3] = _4;
    }
    operator T*( void ) // 重载类型转换函数
    {
        return m;
    }
    Tuple operator+( const Tuple& obj ) const// 重载减号
    {
        Tuple ret;
        ret.m[0] = m[0] + obj.m[0];
        ret.m[1] = m[1] + obj.m[1];
        ret.m[2] = m[2] + obj.m[2];
        ret.m[3] = m[3] + obj.m[3];
        return ret;
    }
    Tuple operator-( const Tuple& obj ) const// 重载减号
    {
        Tuple ret;
        ret.m[0] = m[0] - obj.m[0];
        ret.m[1] = m[1] - obj.m[1];
        ret.m[2] = m[2] - obj.m[2];
        ret.m[3] = m[3] - obj.m[3];
        return ret;
    }
    Tuple& operator+=( const Tuple& obj )
    {
        m[0] += obj.m[0];
        m[1] += obj.m[1];
        m[2] += obj.m[2];
        m[3] += obj.m[3];
        return *this;
    }
    //-------------------------------------
    T m[4];
    struct
    {
        T x, y, z, w;
    };
    struct
    {
        T r, g, b, a;
    };
};
// 定义数据类型
typedef Tuple<float, 2> Vector2F, Point2F, Size2F;
typedef Tuple<float, 3> Vector3F, Color3F, Point3F;
typedef Tuple<float, 4> Vector4F, Color4F;

这里用Tuple表示一个通用的类模板,第一个参数表示类型,如floatdouble等,第二个参数表示成员的个数。我们通过特化234个成员个数的类模板来分别定义这些行为。最后定义了Vector2F等一些常见的类型。你们看,是不是比较好地达到了要求?

此外,这里使用到了union联合体的相关用法,在下一次我将向大家介绍union的妙用。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics