ベクトルの要素へのアクセス 〜その3〜
#include <boost/iterator_adaptors.hpp> #include <d3dx9.h> struct my_vec{ float x, y, z; }; //----------------------------------------------------------------------------- template<typename T> struct vec_traits; template<> struct vec_traits<my_vec>{ static const int dimension = 3; typedef float value_type; typedef my_vec vec_type; struct iterator : public boost::iterator_adaptor< iterator, value_type*, value_type&, boost::random_access_traversal_tag >{ iterator(vec_traits::value_type* f) : iterator_adaptor_(f){} }; static const value_type& get_x(const vec_type& v){ return v.x; } static void set_x(vec_type& v, const value_type& value){ v.x = value; } static iterator begin(vec_type& v){ return iterator(&v.x); }; static iterator end(vec_type& v){ return iterator( &(v.z) + 1 ); }; }; template<> struct vec_traits<D3DVECTOR>{ static const int dimension = 3; typedef float value_type; typedef D3DVECTOR vec_type; struct iterator : public boost::iterator_adaptor< iterator, value_type*, value_type&, boost::random_access_traversal_tag >{ iterator(vec_traits::value_type* f) : iterator_adaptor_(f){} }; static const value_type& get_x(const vec_type& v){ return v.x; } static void set_x(vec_type& v, const value_type& value){ v.x = value; } static iterator begin(vec_type& v){ return iterator(&v.x); }; static iterator end(vec_type& v){ return iterator( &(v.z) + 1 ); }; }; template<> struct vec_traits<D3DXVECTOR3> : public vec_traits<D3DVECTOR>{}; //----------------------------------------------------------------------------- template<typename T> struct vec_value_type{ typedef typename vec_traits<T>::value_type type; }; template<typename T> struct vec_dimension{ static const int value = vec_traits<T>::dimension; }; template<typename T> struct vec_iterator{ typedef typename vec_traits<T>::iterator type; }; template<typename T> struct vec_get_x{ const typename vec_value_type<T>::type& operator ()(const T& v){ return vec_traits<T>::get_x(v); } }; template<typename T> struct vec_set_x{ void operator ()(T& v, const typename vec_value_type<T>::type& value){ vec_traits<T>::set_x(v, value); } }; //----------------------------------------------------------------------------- template<typename T> const typename vec_value_type<T>::type& get_x(const T& v){ return vec_get_x<T>()(v); } template<typename T> void set_x(T& v, const typename vec_value_type<T>::type& value){ vec_set_x<T>()(v, value); } template<typename T> typename vec_iterator<T>::type begin(T& v){ return vec_traits<T>::begin(v); } template<typename T> typename vec_iterator<T>::type end(T& v){ return vec_traits<T>::end(v); } template<typename T> struct vec_range{ typedef T vec_type; typedef typename vec_iterator<T>::type iterator; iterator begin(){ return ::begin(v); } iterator end(){ return ::end(v); } vec_range(vec_type& rhs) : v(rhs){} private: vec_type& v; }; template<typename T> vec_range<T> make_vec_range(T& v){ return vec_range<T>(v); } template<typename T> typename vec_iterator<T>::type::value_type at(T& v, std::size_t n){ return vec_traits<T>::begin(v)[n]; } //----------------------------------------------------------------------------- int main(){ my_vec vec; set_x(vec, 0.0f); assert(vec.x == get_x(vec) ); at(vec, 0) = 0.0f; at(vec, 1) = 1.0f; at(vec, 2) = 2.0f; auto range = make_vec_range(vec); std::for_each(range.begin(), range.end(), [](float value){ std::cout << value << " "; }); std::valarray<float> val_vec(3); // DirectX D3DVECTOR d3d_vec; set_x(d3d_vec, 0.0f); assert(d3d_vec.x == get_x(d3d_vec) ); D3DXVECTOR3 d3dx_vec; set_x(d3dx_vec, 0.0f); assert(d3dx_vec.x == get_x(d3dx_vec) ); return 0; }
変に考えないで素直に書いてみました。
大元に、 vec_traits があり、各 traits → 各関数につなげて呼び出しを行います。
各 traits で template の特殊化をして実装を行ってもいいし、関数のオーバーロードを使用して実装してもいいので、割と拡張子がしやすいんじゃないかと。
あちこちで実装するのがめんどくさいのであれば、vec_traits にまとめてしまえばいいわけですし。
何はともあれ、最初にあれこれ頭の中で考えるよりも、先に大きい風呂敷を広げて、畳んだ方がいいですね。