スポンサーリンク

| キーワード:

色々な型に対応できる関数を作る(1)構造体対応

1.基本

以下のようなコードがある。vec_tは三次元のベクトル型で、lengthはその長さを計算する

len.hpp

#pragma once

struct 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 ); }

source.cpp

#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にしか対応していない。(故に読みやすいのだが。)

2.テンプレート化

length関数をテンプレート化する

len.hpp

#pragma once

struct 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 ); }

source.cpp

これで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がないときはどうすればいいのか。

3.テンプレートでデータ取得用の関数を指定する

len.hpp

#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) ); }

source.hpp

#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を定義すればどんな型でも使える。

続く…

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: