お久しぶりです。今回もよろしくお願いいたします。
早速ですが、今回お聞きしたいことは、C/C++ゲーム開発におけるテンプレート(メタプログラミング)の活用方法です。
おかげさまで、クラスを用いたゲーム開発の理解はかなり深まったと思います。ポリモーフィズムやインターフェースなども、理解して使えるようになりました。
そこで次のステップとして、テンプレートについて理解を深めたいなと思っています。
ところがテンプレートに関する説明は、そのほとんどが
int add(int a, int b)とdouble add(double a, double b)の二つをオーバーロードするのって面倒でしょ?だったらふたつまとめて、templete<typename T> T add(T a, T b)にしよう!
みたいな記述が多く、それだけ?となってしまって、正直そこまでメリットを感じないですし、それでこれをどう使えと...となっております。
しかし、実際STLコンテナなどでテンプレートが使われてます。
テンプレートを使用することにメリットが多いから、目にする機会が多いのだと思います。
ですが、実際にゲーム開発でどのように利用されてるのか、そういった記述を見つけることができませんでした。
そこで、皆さんにお聞きしたいのは、実際にゲームプログラミングをしている中で、どのようにテンプレートを使用していますか?ということです。
STLコンテナで使ってるじゃないか、という話ではなく、自分でtempleteという単語を入力する機会についての話です。
ゲームには、プレイヤークラスや敵クラス、アイテムクラスなどがあるとして、すべてのクラスはupdate()関数を持っているとすると、
テンプレートでT t; t->update();みたいなことができて、一括してアップデートできるようになるのかな?などと思ったのですが、
別にそんなことするまでもなく、ポリモーフィズムで十分じゃないか?という結論になりました。
まったく活用方法のイメージがわきません。皆さんはどのようにテンプレートを使っていますか?
抽象的なしょうもない質問と思われるかもしれませんが、よろしくお願いします。
テンプレートを使ったゲーム開発
Re: テンプレートを使ったゲーム開発
趣味でゲームプログラミングをしていますが、あまりテンプレートを使う機会はないですね(あくまで個人の感想)。
ときどき、 というような関数は使いますけど・・・。
実際に書くとしたら
こういう感じですかね・・・。
ときどき、 というような関数は使いますけど・・・。
実際に書くとしたら
template< class T >
struct Rect_t
{
T top, bottom;
T left, right;
// その他のコンストラクタ・オペレータのオーバーロード等を実装する
};
// こうやって使う
void test()
{
auto rect_int = Rect_t< int > {}; // 座標が int 型のRect_t
auto rect_float = Rect_t< float > {}; // 座標が float 型のRect_t
auto rect_double = Rect_t< double > {}; // 座標が double 型のRect_t
}
初心者です
Re: テンプレートを使ったゲーム開発
Rittai_3Dさん、返信ありがとうございます。
そうですか...テンプレートはあまり使用されないのですね。
ゲームプログラミングにおいて使う機会がなのであれば、無理にテンプレートを使う必要はないので、それならこのままゲーム開発を続けていこうと思います。
ソースコードを提示していただき、ありがとうございます。
せっかく作っていただいたにもかかわらず、このようなことを言うのは大変申し訳ないのですが、
やはりそのようにテンプレートを使うことに、いまいちメリットを感じることができませんでした...
最悪全部キャスト変換できるんだから、doubleで宣言しておけばいいのでは?と思いました。
僕の経験や知識が不足しているために、理解しきれていないところがあると思いますので、
(実際、constexprもautoもいまいちわかっておりませんでした...)
もう少し、いろいろと自分で調べて勉強してみようと思います。
Rittai_3Dさん、本当にありがとうございました。
そうですか...テンプレートはあまり使用されないのですね。
ゲームプログラミングにおいて使う機会がなのであれば、無理にテンプレートを使う必要はないので、それならこのままゲーム開発を続けていこうと思います。
ソースコードを提示していただき、ありがとうございます。
せっかく作っていただいたにもかかわらず、このようなことを言うのは大変申し訳ないのですが、
やはりそのようにテンプレートを使うことに、いまいちメリットを感じることができませんでした...
最悪全部キャスト変換できるんだから、doubleで宣言しておけばいいのでは?と思いました。
僕の経験や知識が不足しているために、理解しきれていないところがあると思いますので、
(実際、constexprもautoもいまいちわかっておりませんでした...)
もう少し、いろいろと自分で調べて勉強してみようと思います。
Rittai_3Dさん、本当にありがとうございました。
Re: テンプレートを使ったゲーム開発
#もう解決になってた。
メタな使い方だと容量とかコンパイル時間とか予想外の状況になったりするので多用はしないですね。
スケジュール大事。
インターフェースの継承だとトップダウンオンリーですが
テンプレートを使うとトップダウンとボトムアップを組み合わせる自由度が上がります。
こんな具合にstd::for_eachを使うと任意のメンバ関数を呼び出せるわけですが
同様の仕組みで、更新関数や描画関数として任意のメンバ関数を呼び出せるマネージャクラスなんてのも作れます。
そんなとき自分でtempleteという単語を入力します。
任意のメンバ関数を更新関数や描画関数にできれば継承が要らなくなって
継承を別の用途(ガベージコレクタ的なこととか)に使うことができるようになります。
組み合わせの自由度が高いと、複雑なものも分解しやすく単純化しやすいです。
コードが読みやすくなるし、モジュール化も進みます。
メタな使い方だと容量とかコンパイル時間とか予想外の状況になったりするので多用はしないですね。
スケジュール大事。
インターフェースの継承だとトップダウンオンリーですが
テンプレートを使うとトップダウンとボトムアップを組み合わせる自由度が上がります。
#include <iostream>
#include <algorithm>
using namespace std;
struct Base
{
virtual void Update() = 0;
};
struct ClassA : public Base
{
int index;
ClassA(int i) : index(i) {};
void Update() override
{
cout << "ClassA::Update(" << index << ")" << endl;
}
void UpdateA()
{
cout << "ClassA::UpdateA(" << index << ")" << endl;
}
};
void AdaptA(ClassA &t) {
t.UpdateA();
}
struct AdaptorA {
void operator()(ClassA &t) {
t.UpdateA();
}
};
int main()
{
Base *a1[] = { new ClassA(1), new ClassA(2), new ClassA(3) };
ClassA a2[] = { 4, 5, 6 };
// 継承ではインターフェースとして定義されたメンバ関数しか呼び出せない
for (Base *b : a1) b->Update();
// テンプレートを使うと(間接的だが)任意のメンバ関数を随時呼び出せる
for_each(begin(a2), end(a2), AdaptA); // 関数
for_each(begin(a2), end(a2), AdaptorA()); // 関数オブジェクト
for_each(begin(a2), end(a2), [](ClassA &o) { o.UpdateA(); }); // ラムダ式
}
同様の仕組みで、更新関数や描画関数として任意のメンバ関数を呼び出せるマネージャクラスなんてのも作れます。
そんなとき自分でtempleteという単語を入力します。
任意のメンバ関数を更新関数や描画関数にできれば継承が要らなくなって
継承を別の用途(ガベージコレクタ的なこととか)に使うことができるようになります。
組み合わせの自由度が高いと、複雑なものも分解しやすく単純化しやすいです。
コードが読みやすくなるし、モジュール化も進みます。