Curiously Recursive Pattern Template (CRTP)を採用して、アプリケーションに一種の Factory を実装しようとしています。
この素敵な投稿に続いて、自分のバージョンの CRTP の開発を開始しました。CRTP を使用すると、気になるテンプレートのサブクラスとして宣言するだけで、ファクトリ プロダクトの新しい実装を登録できます。以下に、質問の例と非常によく似た、使用しているコードの簡単な例を貼り付けました。
class abstractProduct {
...
};
template <uint8_t TYPE, typename DERIVED>
class crtp : public abstractProduct{
uint8_t mType;
protected:
crtp() : mType(CRTP_ID){}
public:
enum { _CRTP_ID = TYPE };
static const abstractProduct* get(){
static DERIVED* sInstance = new DERIVED();
return sInstance;
}
static const uint8_t CRTP_ID;
};
template <uint8_t TYPE, typename DERIVED>
const uint8_t crtp<TYPE, DERIVED>::CRTP_ID = Factory::reg(crtp<TYPE, DERIVED>::_CRTP_ID, &crtp<TYPE, DERIVED>::get);
typedef const abstractProduct* (*f_dispenser)(void);
class Factory {
static std::map<uint8_t, f_dispenser>* sDict;
public:
static uint8_t reg(uint8_t shID, f_dispenser dispenser);
static bool has(uint8_t shID);
static const abstractProduct* dispense(uint8_t shID);
};
class sub : public crtp<1, sub>{
friend class crtp<1, sub>;
protected:
sub();
public:
virtual ~sub();
};
ご覧のとおり、 class を宣言したらsub
、 parameters を使用して新しい crtp テンプレートを作成する必要があります<1, sub>
。テンプレート クラスは、crtp コンストラクターでも参照されるcrtp
static を宣言します。const uint8_t CRTP_ID
静的定数変数は、次のようにインスタンス化されます。
template <uint8_t TYPE, typename DERIVED>
const uint8_t crtp<TYPE, DERIVED>::CRTP_ID = Factory::reg(crtp<TYPE, DERIVED>::_CRTP_ID, &crtp<TYPE, DERIVED>::get);
CRTP_ID
最初のメイン命令が実行される前に初期化されることを保証する必要があります。クラスの初期化中CRTP_ID
にファクトリに登録されます
現在、ndk r8d と sdk 21.0.1 を使用しています。
今問題。プロジェクトをデフォルトの gcc コンパイラでコンパイルすると、すべて正常に動作し、crtp のサブクラスが自動的に登録されます。プロジェクトを Android ツールチェーンでコンパイルすると、サブクラスは登録されません。
私が間違っていることは何ですか?
編集
私の Android アプリケーションは、NativeActivityを使用して C++ で完全に実装されています。OpenGLEs コンテキストを作成して処理する状態オブジェクトを定義しました。ウィンドウを表示する準備ができたことが Android から状態に通知されると、GL コンテキストが作成され、レンダリングされるメッシュが読み込まれます。
state.cpp
case APP_CMD_INIT_WINDOW:
LOGI("[state]The window is being shown, get it ready.");
sSurfManager->init(app->window, app->activity->assetManager);
surfacemanager.cpp
int SurfaceManager::init(ANativeWindow* win, AAssetManager* man){
....
this->mModel = GeometryManager::loadModel("cube.ply", man);
}
はGeometryManager::loadModel
、ファイルからジオメトリとマテリアルをロードします。メッシュで見つかった各マテリアルに対して、この関数を使用して新しい MaterialData オブジェクトを作成します。
static MaterialData* create(aiMaterial* material);
MaterialData::create 関数内で、マテリアルをレンダリングするための適切なシェーダーを取得するために Factory が照会されます。
MaterialData* MaterialData::create(aiMaterial* material){
...
result->setShader(ShaderFactory::dispense(1));
}
シェーダーを取得する正しい方法ではないことはわかっていShaderFactory::dispense(1)
ますが、シェーダーが工場で作成されているかどうかを確認するために使用しています。
ありがとう!