スポンサーリンク
続き
せっかくテンプレートを使用しているのに、GETTERの特殊化が長すぎる問題がある。
今回はlength関数しか使用していないので特にそう感じる。x,y,zの要素をとる関数が、例えばinnner,outer,distance...等沢山あれば気にならない。
とはいえ、短いほうがいいのは間違いないので、できる限り少ない行数で特殊化できないか考える。
あらかじめ、要素がx,y,zの時に使えるaccess_xyzと、X,Y,Zの時に使えるaccess_XYZを用意しておく。
#pragma once ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // プライマリテンプレート template<typename T> struct GETTER;
////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // テンプレート
template<typename T> struct access_xyz { using arg_t = T; using carg_t = const T; static inline double& X(arg_t& v) { return v.x; } static inline double& Y(arg_t& v) { return v.y; } static inline double& Z(arg_t& v) { return v.z; } static inline const double& X(carg_t& v) { return v.x; } static inline const double& Y(carg_t& v) { return v.y; } static inline const double& Z(carg_t& v) { return v.z; } };template<typename T> struct access_XYZ { using arg_t = T; using carg_t = const T; static inline double& X(arg_t& v) { return v.X; } static inline double& Y(arg_t& v) { return v.Y; } static inline double& Z(arg_t& v) { return v.Z; } static inline const double& X(carg_t& v) { return v.X; } static inline const double& Y(carg_t& v) { return v.Y; } static inline const double& Z(carg_t& v) { return v.Z; } };////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // ポインタ版 (変更なし) template<typename T> struct GETTER<T*> { using arg_t = T *; using carg_t = const T*; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } }; template<class T, std::size_t N> struct GETTER<T[N]> { using arg_t = T[N]; using carg_t = const T[N]; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } }; template<typename T, std::size_t N> struct GETTER<std::array<T, N> > { using arg_t = std::array<T, N> &; using carg_t = const std::array<T, N> &; static inline double& X(arg_t v) { return v[0]; } static inline double& Y(arg_t v) { return v[1]; } static inline double& Z(arg_t v) { return v[2]; } static inline const double& X(carg_t v) { return v[0]; } static inline const double& Y(carg_t v) { return v[1]; } static inline const double& Z(carg_t v) { return v[2]; } }; ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // 関数本体 template< typename T, class G = GETTER<T> > double length(const T & v) { return sqrt( G::X(v) * G::X(v) + G::Y(v) * G::Y(v) + G::Z(v) * G::Z(v) ); }
使用したい構造体に合わせて、継承元を変える。
#include <array> #include "len.hpp" ////////////////////////////////////////////////////// // 型1 struct vec_t { double x, y, z; }; ////////////////////////////////////////////////////// // 型2 struct VEC_t { double X, Y, Z; }; //特殊化1 template<> struct GETTER<vec_t> :public access_xyz<vec_t> {};
//特殊化2 template<> struct GETTER<VEC_t> :public access_XYZ<VEC_t> {}; //エントリポイント int main() { double L; vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; L = length(vv); std::cout << L << std::endl; VEC_t VV; VV.X = 1; VV.Y = 1; VV.Z = 1; L = length(VV); std::cout << L << std::endl; int i; std::cin >> i; }