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
请按任意键继续. . .