以下のようなコードがある。vec_tは三次元のベクトル型で、lengthはその長さを計算する
#pragma oncestruct vec_t { double x, y, z; };double length(const vec_t& v) { return sqrt( v.x * v.x + v.y * v.y + v.z * v.z ); }
#include <iostream> #include "len.hpp" int main() { vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; double dbl = length(vv); std::cout << dbl << std::endl; int i; std::cin >>i; }
lengthはシンプルで可読性が高いが、移植性には欠ける。
具体的にはvec_tにしか対応していない。(故に読みやすいのだが。)
length関数をテンプレート化する
#pragma oncestruct vec_t { double x, y, z; };template<typename T> double length(const T& v) { return sqrt( v.x * v.x + v.y * v.y + v.z * v.z ); }
これでx,y,zというメンバ変数がpublicにあればコンパイルできる。
#include <iostream> #include "len.hpp"struct xyz_t { double x, y, z; };int main() { double L; vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; L = length(vv); std::cout << L << std::endl; xyz_t xyz; xyz.x = 1; xyz.y = 1; xyz.z = 1; L = length(xyz); std::cout << L << std::endl; int i; std::cin >>i; }
ではx,y,zがないときはどうすればいいのか。
#pragma once//デフォルトの型 struct vec_t { double x, y, z; };//プライマリテンプレート template<typename T> struct GETTER;//特殊化1(デフォルトの型) template<> struct GETTER<vec_t> { using arg_t = vec_t; using carg_t = const vec_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, 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 <iostream> #include "len.hpp" //自作の型 struct XYZ_t { double X, Y, Z; };
//特殊化2(自作の型用) template<> struct GETTER<XYZ_t> { using arg_t = XYZ_t; using carg_t = const XYZ_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; } };//エントリポイント int main() { double L; vec_t vv; vv.x = 1; vv.y = 1; vv.z = 1; L = length(vv); std::cout << L << std::endl; XYZ_t xyz; xyz.X = 1; xyz.X = 1; xyz.X = 1; L = length(xyz); std::cout << L << std::endl; int i; std::cin >> i; }
これでGETTERを定義すればどんな型でも使える。
続く...