天天看点

N维向量的模板实现

code:

vectorBase.hpp:一些低维特化、

#include <iostream>

using namespace std;

// for any dimensions other than

// specified below, this struct will

// be used

template<class T,int N>

struct vector_base

{

T m_data[N];

};

// specialization for a 2D vector

// provides the vector with .x and .y variables

template<class T>

struct vector_base<T, 2>

{

union

{

struct

{

T x, y;

};

T m_data[2];

};

vector_base() { }

vector_base( const T& _x, const T& _y ) : x(_x), y(_y) { }

};

// specialization for a 3D vector

// provides the vector with .x, .y, and .z variables

template<class T>

struct vector_base<T,3>

{

union

{

struct

{

T x, y, z;

};

T m_data[3];

};

vector_base() { }

vector_base( const T& _x, const T& _y, const T& _z ) : x(_x), y(_y), z(_z) { }

};

// specialization for a 4D vector

// provides the vector with .w, .x, .y, and .z variables

template<class T>

struct vector_base<T,4>

{

union

{

struct

{

T w, x, y, z;

};

T m_data[4];

};

vector_base() { }

vector_base( const T& _w, const T& _x, const T& _y, const T& _z ) : w(_w), x(_x), y(_y), z(_z) { }

};

// a base for a vector that doesn't specialize vector_base

// provides the vector with .r, .g, .b, and .a variables

template<class T>

struct vector_color

{

union

{

struct

{

T r, g, b, a;

};

T m_data[4];

};

vector_color() { }

vector_color( const T& _r, const T& _g, const T& _b, const T& _a ) : r(_r), g(_g), b(_b), a(_a) { }

};

vectorTemplate.hpp

类的定义实现:

#include <cassert>

#include <cmath>

#include "vectorBase.hpp"

// the vector itself

// with its variable type: T

// its dimensions: N

// and its core: base

template<class T, int N, class base = vector_base<T,N> >

class vector_t : public base

{

public:

// handy typedef:

typedef vector_t<T,N> my_type;

// default constructor

vector_t() { }

// two-arg constructor for 2D vectors

vector_t( const T& x, const T& y ) : base(x,y) { }

// three-arg constructor for 3D vectors

vector_t( const T& x, const T& y, const T& z ) : base(x,y,z) { }

// four-arg constructor for 4D vectors

vector_t( const T& w, const T& x, const T& y, const T& z ) : base(w,x,y,z) { }

//

// Note, if the programmer tries to construct a 3D vector using a two-arg constructor,

// the compiler will complain that base does not have enough arguments. Nifty :)

//

// constructor for same-dimensional, differing-typed vectors

// use the keyword "explicit"

template<class T2, class B2>

vector_t( const vector_t<T2,N,B2>& rhs )

{

for ( int i = 0; i < N; i++ )

m_data[i] = static_cast<T>( rhs.m_data[i] );

}

// constructor with a same-dimensional array of a differing type

template<class T2>

// vector_t( const T2 data[N] )

vector_t( const T2 (&data)[N] )

{

for ( int i = 0; i < N; i++ )

m_data[i] = static_cast<T>( data[i] );

}

// assignment operation for same-dimensional, differing-typed vectors

template<class T2, class B2>

my_type& operator = ( const vector_t<T2,N,B2>& rhs )

{

for ( int i = 0; i < N; i++ )

m_data[i] = static_cast<T>( rhs.m_data[i] );

return *this;

}

// assignment operation for a an array of a differing type

template<class T2>

my_type& operator = ( const T2 data[N] )

{

for ( int i = 0; i < N; i++ )

m_data[i] = static_cast<T>( data[i] );

return *this;

}

//

// getters

//

T& operator [] ( const int idx )

{

assert( 0 <= idx && idx < N ); // or throw an exception

return m_data[ idx ];

}

const T& operator [] ( const int idx ) const

{

assert( 0 <= idx && idx < N );

return m_data[ idx ];

}

//

// overloads

//

// negation

my_type operator - () const

{

my_type result;

for ( int i = 0; i < N; i++ )

result.m_data[i] = -m_data[i];

return result;

}

// addition of two same-dimensional, differing-typed vectors

template<class T2,class B2>

my_type operator + ( const vector_t<T2,N,B2>& rhs ) const

{

my_type result;

for ( int i = 0; i < N; i++ )

result.m_data[i] = m_data[i] + rhs.m_data[i];

return result;

}

// subtraction of two same-dimensional, differing-typed vectors

template<class T2,class B2>

my_type operator - ( const vector_t<T2,N,B2>& rhs ) const

{

my_type result;

for ( int i = 0; i < N; i++ )

result.m_data[i] = m_data[i] - rhs.m_data[i];

return result;

}

// scalar multiplication of two same-dimensional, differing-typed vectors

template<class T2>

my_type operator * ( const T2& rhs ) const

{

my_type result;

for ( int i = 0; i < N; i++ )

result.m_data[i] = static_cast<T>( m_data[i] * rhs );

return result;

}

// scalar division of two same-dimensional, differing-typed vectors

template<class T2>

my_type operator / ( const T2& rhs ) const

{

my_type result;

for ( int i = 0; i < N; i++ )

result.m_data[i] = m_data[i] / rhs;

return result;

}

//

// operations:

//

// calculate the dot product of two differing-typed vectors

template<class T2,class B2>

T dot( const vector_t<T2,N,B2>& rhs ) const

{

T result = static_cast<T>( 0 );

for ( int i = 0; i < N; i++ )

result += static_cast<T>( m_data[i] * rhs.m_data[i] );

return result;

}

// squared length of the vector

T length_sq() const

{

return this->dot( *this );

}

// length of the vector

T length() const

{

return std::sqrt( this->dot( *this ) );

}

// return a normalized vector

my_type normalize() const

{

return *this / this->length();

}

// and for other operations not mentioned,

// you can provide a functor to do the rest

template<class F>

my_type predicate( const F& f ) const

{

my_type result;

for ( int i = 0; i < N; i++ )

result.m_data[i] = f( m_data[i] );

return result;

}

};

// handy write to ostream function:

template<class T, int N, class B>

std::ostream& operator << ( std::ostream& out, const vector_t<T,N,B>& v )

{

for ( int i = 0; i < N; i++ )

out << v.m_data[ i ] << ' ';

return out;

}

测试程序:

main.cpp

#include "TemplateFunctionVector.hpp"

#include "vectorTemplate.hpp"

int main( int c, char* v[] )

{

//

// the vector_t declaration is already looking ugly,

// provide some typedefs:

//

// simple geometric types:

typedef vector_t<double,2> v2;

typedef vector_t<int,2> v2i;

// graphics specific color types:

typedef unsigned char ui8;

typedef vector_t<float, 4, vector_color<float> > colorf;

typedef vector_t<int, 4, vector_color<int> > colori;

typedef vector_t<ui8, 4, vector_color<ui8> > color;

//

// begin some tests:

//

//

// test 1:

//

{

std::cout << "test1:/n";

v2 pt1_d = v2( 3.0, 3.0 );

v2i pt2_i( 1, 2 );

v2 pt2 = (pt1_d + pt2_i) * 0.5;

std::cout << pt2 << "/n/n";

}

//

// test 2:

//

{

std::cout << "test2:/n";

// v2 pt1 = v2( 1.0, 2.0, 3.0 ); // C2661: no overloaded function takes three arguments

v2 pt1 = v2( 1.0, 2.0 );

v2i pt2i = v2i( 3, 4 );

v2 pt3( pt1 ); // test copy constructor

std::cout << pt3 << '/n';

pt3 = pt1; // test assignment operator

std::cout << pt3 << '/n';

pt3 = pt2i; // test assignment operator

std::cout << pt3 << '/n';

pt3.y = pt3.x; // test aliases

std::cout << "/n/n";

}

//

// test 3:

//

{

std::cout << "test3:/n";

colorf my_color( 0.0, 1.0, 0.5, 1.0 );

std::cout << my_color << '/n';

// test alias:

my_color.r = 0.25;

std::cout << my_color << '/n';

color hardware_color( my_color * 255 );

std::cout << colori( hardware_color ) << '/n'; // cast to int to display ints instead of chars

std::cout << "/n/n";

}

//

// test 4:

//

{

std::cout << "test4:/n";

typedef vector_t<double,5> v5;

// vector_t doesn't have a five arg constructor, so

// we will have to use arrays, (or just implement a 5-arg constructor)

double arr[] = { 1.0, 2.0, 3.0, 4.0, 5.0 };

v5 p1( arr );

v5 p2 = arr;

std::cout << p1 << '/n' << p2 << '/n' << (p1 + p2).normalize() << '/n';

// v5 p3( { 1.0, 2.0, 3.0, 4.0, 5.0 } ); // error :(

std::cout << "/n/n";

}

system("PAUSE");

return 0;

}

测试输出:

test1:

2 2.5

test2:

1 2

1 2

3 4

test3:

0 1 0.5 1

0.25 1 0.5 1

63 255 127 255

test4:

1 2 3 4 5

1 2 3 4 5

0.13484 0.26968 0.40452 0.53936 0.6742

请按任意键继续. . .