テンプレートとvirtual

しばらく、忙しかったり疲れてたりして更新してませんでした。GPUPPURのほうは予定よりも遅れていますが大きな問題も特に無く開発が進んでいます。


GPUPPURのようにDirectXを使った実装とOpenGLを使った実装の両方を使いたい場合は、普通以下のように書くと思いますが


class gpuppur
{
virtual void render() = 0;
};

class gpuppur_implement_with_directx : public gpuppur
{
void render()
{
}
}

class gpuppur_implement_with_opengl : public gpuppur
{
void render()
{
}
}

これだとvirtual関数だからインライン展開されなくて遅いです。

非virtualに(さらにheaderに関数定義)すればインライン展開もされ高速化できますが、virtualのような便利さ(この例では実行時にgpuppurをopengl版とdirectx版に切り替えることができる)ができません。インライン展開と同等の速さでvirtualと同じことができるということはほぼ無理でしょう。windows以外では必ずopengl版を使わないといけないというふうに、コンパイル時にどちらにするか決定することができる場合もあります。つまり、gpuppurクラスを使う人がvirtualにするか非virtualにするか決定できればいいわけです。

以下のようにテンプレートを使って基底クラスを指定できるようにすれば、virtualか非virtualかを切り替えることができます。


template
class gpuppur_implement_with_directx : public Base
{
public:
void render();
};

class virtual_gpuppur
{
public:
virtual virtual_gpuppur() = 0;
virtual void render() = 0;
};

class void_
{
};

typedef gpuppur_implement_with_directx gpr_dx_v; //virtual
typedef gpuppur_implement_with_directx gpr_dx; //非virtual

virtual_gpuppur* phoge = new gpr_dx_v;

gpuppurにはdirectx実装とopengl実装があるわけですが、それぞれの実装クラスのrender関数でデバッグ時はrenderを呼び出す前

と後に不変条件をチェックしたいとします。その不変条件のチェックは各実装で共通なのでgpuppurクラスのrender関数から各実

装のrenderをにまとめておけばいいのですが、gpuppurクラスを基底クラスにするとvirtualを使わない限り基底クラスから派生ク

ラスの関数を呼べません。また、directx実装とopengl実装の各クラスからgpuppurの関数を呼び出したいとします。もちろん、先

ほど書いたようにvirtual/非virtualを切り替えることができるようにしたいのです。


template
class gpuppur_implement_with_opengl : public Base
{
public:
void render()
{
vector3 = Base::get_camera_position();
...
}
};

template
class gpuppur_implement_with_dx : public Base
{
public:
void render()
{
vector3 = Base::get_camera_position();
...
}
};

template
class gpuppur_base : public Base
{
public:
vector3 get_camera_position();
};

template class Implement>
class gpuppur
{
public:
template
class c : public Implement >

typedef Implement > base;

void render()
{
check_render_ready();
base::render();
check_any_err();
}
};

//仮想関数を持つgpuppurのdirectx実装とopengl実装
typedef gpuppur::c gpuppur_gl;
typedef gpuppur::c gpuppur_dx;

virtual_gpuppur* pgpuppur = is_gl() ? (virtual_gpuppur*)new gpuppur_gl() : new gpuppur_dx();

//仮想関数を持たないgpuppurのdirectx実装とopengl実装
gpuppur::c static_gpuppur_gl;
gpuppur::c static_gpuppur_dx;

これで、gpuppurをvirtual版、非virtual版と切り替えることができ、gpuppurのopengl実装とdirectx実装に共通な部分はきちん

と一箇所に集まってます。
もしgpuppurの3dfx Glide実装を作る場合でもGlide依存のrender()関数とかだけを実装し、後はgpuppurテンプレート引数にGlide実装のテンプレートクラスを指定すれば、gpuppurのGlide実装が出来上ります。