0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ゲームプログラマのための設計:ユーティリティ関数の置き場所

Last updated at Posted at 2024-10-22

ゲームプログラマのための設計シリーズ:実装詳細編の記事です。

概要

  • ユーティリティ関数は非メンバ関数にしよう
  • ただし、テンプレートを用いた静的Strategyパターンを用いるときは例外的に静的メンバ関数を利用する

本文

基本は非メンバ

算術計算など、使用目的を限定しないいわゆるユーティリティ関数の置き場としては以下の二か所が考えられます。

// 非メンバ関数版
namespace MathUtilityNS
{
	int Add(int, int);
	int Sub(int, int);
}
// 静的メンバ関数版
class MathUtilityClass
{
public:
	static int Add(int, int);
	static int Sub(int, int);
};

実装する側としては大した違いはないのですが、利用側としては名前空間ならそれを省略できるのでそちらを優先してあげたいです。

void func()
{
	// 名前空間なら、usingで省略できる
	using namespace MathUtilityNS;
	Add(1, 2);

	// 静的関数版はクラス名を省略できない
	MathUtilityClass::Add(1, 2);
}

※余談:実装する側としての違いの例

  • 非メンバ関数版はうっかりinlineをつけ忘れるかもしれない
namespace MathUtilityNS
{
	int Add(int lhs, int rhs) { return lhs + rhs; }  // inlineをつけてないのにインラインで定義を書くと、複数の.cppから参照されたときODR違反
}

class MathUtilityClass
{
public:
	static int Add(int lhs, int rhs) { return lhs + rhs; } // メンバ関数はインラインで書いてもODR違反にならない
};
  • メンバ変数を持つクラスの静的メンバ関数とする場合、そのクラスのprivate変数に触れる
class Vector2
{
	using Self = Vector2;
	float mX, mY;
public:
	explicit Vector2(float x, float y) : mX(x), mY(y) {}
	static Self Add(const Self& lhs, const Self& rhs)
	{
        // 静的であってもメンバ関数なのでprivateに触れる
		return Self{ 
			lhs.mX + rhs.mX, 
			lhs.mY + rhs.mY 
		};
	}
};
  • メンバ関数の実装を.cppに書く場合毎回クラス名::を書かないといけなくて面倒

静的メンバ関数が必要になるケース

テンプレート引数を差し替えることで、関数内の処理を部分的に切り替えるStrategyパターンというデザインパターンがあります。(動的ポリモーフィズムを利用する方法と比較して静的Strategyパターンと呼ばれたりします。Policyパターンと呼ばれることも)
これを利用したいは非メンバ関数ではどうにもならないので、静的メンバ関数を利用することになります。

// MathPolicyに与えたクラスのAdd/Sub関数を使って計算する関数
// C++20以降ではConceptを利用するのがベター
template<typename MathPolicy>
int calc(int a, int b, int c)
{
	// AddとSubの実装を、テンプレート引数で切り替えられる
	const int m = MathPolicy::Add(a, b);
	const int n = MathPolicy::Sub(b, c);
	return m * n;
}

void func()
{
	const int s = calc<MathUtilityClass>(1, 2, 3);
	const int t = calc<MathUtilityClass2>(1, 2, 3); // AddとSubの実装次第で違う結果になる
}

ハードウェアごとにそれぞれ最適な計算方法に丸っと切り替えたいなどといったケースで利用されますが、そのような場面はあまり多くはないでしょう。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?