G.D.M

「 Game Development Memo 」 の略称。 ゲーム開発の備忘録

 

スポンサーサイト 

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

category: スポンサー広告

TB: --    CM: --

#includeでcsvファイルを展開 

そういえば#includeでcsvファイルを展開するテクニックがあったなぁ…
と最近思い出したのでメモ。

test.csvに「0, 1, 2」とデータを記入したうえで

int values[] =
{
#include "test.csv"
};

とすると#includeによりcsvファイルが展開され、
配列のvaluesは values[3] = { 0, 1, 2 } となる。

このテクニックはcsvファイルを更新するたびに
再コンパイルする必要があるため、実行時にファイルを書き換えて
更新させたいようなデータには向いていない。
そのため実行時に書き換えが必要でないようなデータに対して検討すべきである。


- 参考 -
Life like a clown - #include の魔力


スポンサーサイト

category: C++

TB: --    CM: 0

奇妙に再帰したテンプレートパターン 

以前クラスメートとの会話中に出てきて、
「そういえばこんなイディオムあったなぁ…名前だけ知ってるわ」
って感じになったのでメモしておく。

「奇妙に再帰したテンプレートパターン(Curiously Recurring Template Pattern)」は
基底クラスをクラステンプレートにし、派生クラス側はその派生クラス自身の型を
基底クラスのテンプレート部分に指定するということを行う。
これにより派生クラスからインターフェースを自由にカスタマイズすることができる。
このイディオムを使うと、静的メンバもカスタマイズ可能となるため、
その部分が普通の派生と大きく違う部分かもしれない。

私は今までこのイディオムの意図は知らなかったのだが、
どうやら前に作った汎用シングルトンクラスがこのイディオムを
使った形で作成されていたようなので、ここに載せとく。

パターンやイディオムは時々自然に使っていることがあったりするので、
「へぇ…この使い方にそんな名前付いてたんだ」っとなって面白い。

参考
More C++ Idioms/奇妙に再帰したテンプレートパターン(Curiously Recurring Template Pattern)


以下、コード ↓


/* 二重インクルード防止 */
#pragma once


/* ヘッダファイル */
#include <memory>
#include "UtilityDefine.h"


/**

@brief C_GeneralSingleton
汎用的なシングルトンクラスの作成に利用するクラス
このクラスを派生し、派生先でこのクラスをフレンド化させることで利用できる

例:

class C_Hoge : public C_GeneralSingleton<C_Hoge>
{
friend C_GeneralSingleton<C_Hoge>;
}

*/
template<class Derived>
class C_GeneralSingleton
{
public:
static Derived& s_GetInstance();
protected:
C_GeneralSingleton();
virtual ~C_GeneralSingleton();
private:
using ManagementPointer = std::unique_ptr<Derived>; // 内部で生成され、管理されているインスタンスのポインタ型

static Derived* s_CreateInstance(); // この関数を派生クラスで定義することで、生成処理を置き換えることができる
DisallowCopyOfInstance(C_GeneralSingleton);
DisallowMoveOfInstance(C_GeneralSingleton);
};


/* 実装 */
#include "GeneralSingletonImpl.h"



/**

@brief コンストラクタ
@param なし

*/
template<class Derived>
inline C_GeneralSingleton<Derived>::C_GeneralSingleton()
{
}


/**

@brief デストラクタ
@param なし

*/
template<class Derived>
inline C_GeneralSingleton<Derived>::~C_GeneralSingleton()
{
}


/**

@brief 唯一のインスタンスを取得する
@para なし
@return インスタンスの参照

*/
template<class Derived>
inline Derived& C_GeneralSingleton<Derived>::s_GetInstance()
{
static typename Derived::ManagementPointer s_pInstance(Derived::s_CreateInstace());
return *s_pInstance;
}


/**

@brief インスタンスの生成を行う
この関数を派生クラス側で定義することで独自の生成方法を実装できる
@param なし
@return 生成したインスタンスのポインタ

*/
template<class Derived>
inline Derived* C_GeneralSingleton<Derived>::s_CreateInstance()
{
return new Derived();
}



category: C++

TB: --    CM: 0

小粋なカウンタ 

前回、静的メンバを初期化する記事を書いたのでそれに続いてもう1つ。

C++にはイディオムの1つに「小粋なカウンタ(Nifty Counter)」というものがある。
これは静的メンバ変数を利用する前に必ず初期化され、
プログラム終了時、完全に必要がなくなった時点で破棄する
ということが可能なイディオムである。

このイディオムの対象となるのは
std::coutのような他の静的オブジェクトにも利用されそうなクラスである。
使い方次第ではなかなかの恩恵を得ることが可能なので、
頭の片隅にでも置いておくとよいと思う。

参考
More C++ Idioms/小粋なカウンタ(Nifty Counter)
takahi-iの日記 シュワルツカウンタ


以下、プログラム ↓



/* 二重インクルード防止 */
#pragma once


class C_Hoge
{
private:
// コンストラクタ・デストラクタ
C_Hoge() = default;
public:
~C_Hoge() = default;

// 静的メンバ変数
static int* s_pFuga;
};


class C_HogeInitializer
{
public:
// コンストラクタ・デストラクタ
C_HogeInitializer();
~C_HogeInitializer();
};


// ヘッダでインスタンスを作ることで、
// このヘッダをインクルードするたび
// C_HogeInitializerのコンストラクタが呼び出せる
static C_HogeInitializer s_initializer;





/* ヘッダファイル */
#include "Hoge.h"


int* C_Hoge::s_pFuga = nullptr;


// C_HogeInitializerのインスタンス数を数えるカウンタ
static int s_nifty_count = 0;


C_HogeInitializer::C_HogeInitializer()
{
if (::s_nifty_count == 0)
{
// ここでC_Hogeの静的メンバを生成と初期化処理
C_Hoge::s_pFuga = new int;
*C_Hoge::s_pFuga = 0;
}

::s_nifty_count++;
}


C_HogeInitializer::~C_HogeInitializer()
{
::s_nifty_count--;

if (::s_nifty_count == 0)
{
// ここでC_Hogeの静的メンバ変数を終了処理と破棄
delete C_Hoge::s_pFuga;
C_Hoge::s_pFuga = nullptr;
}
}


肝となる部分はヘッダにC_HogeInitializerのインスタンスを
生成している部分である。
これにより、このヘッダをインクルードしたcppごとにインスタンスが作られ、
Hoge.cpp側のs_nifty_countがカウントされる。


category: C++

TB: --    CM: 0

スタティックイニシャライザ 

C++には静的メンバ変数を初期化する構文がない。
しかしそれにとって代わるクラスを作ることは可能であったため作成してみた。

参考
static コンストラクタのようなもの
静的コンストラクタもどき



/* 二重インクルード防止 */
#pragma once


/**

@brief C_StaticInitializer
静的メンバ変数の初期化を行うクラス

*/
template<class T>
class C_StaticInitializer
{
public:
// コンストラクタ
C_StaticInitializer()
{
T::s_StaticInitialize();
}
};





#include <iostream>
#include "StaticInitializer.h"


class C_Hoge
{
public:
static int s_values[256];

// 静的初期化処理
static void s_StaticInitialize()
{
for (auto& rValue : s_values) rValue = 1;
}
};


int C_Hoge::s_values[256];


static C_StaticInitializer<C_Hoge> s_hoge_initializer;


int main()
{
int sum = 0;

for (auto value : C_Hoge::s_values)
{
sum += value;
}

std::cout << sum << std::endl;

return 0;
}


静的メンバ変数を実行時に初期化したい場合に
静的メンバ関数としてs_StaticInitialize関数を定義し、
C_StaticInitializerでそのクラスのインスタンスをグローバルや静的変数などとして
実行時にインスタンスが生成される状況を作ればよい。
そうすることで定義したs_StaticInitialize関数が実行時に呼び出され、
静的メンバ変数を初期化する機会を設けることが可能となる。


category: C++

TB: --    CM: 0

元の型の隠蔽 

最近、クラス内にクラスや構造体を作る場合、
下記のような別名によるアクセス範囲の指定を行うことがよくある。



class C_Hoge
{
private:
class C_Fuga
{
};
public:
using Fuga = C_Fuga;
};


int main()
{
C_Hoge::Fuga fuga; // 別名はpublicなためアクセス可
// C_Hoge::C_Fuga fuga; // 元のクラスはprivateに置かれているのでアクセス不可

return 0;
}



こうすることにより、外部から利用する場合は元の型を知ることなく
利用することになる。また別名からの利用を強要することにもなるため
コードの変更時に外部で元の型を使用している心配がなくなるのも利点だ。
やっていることは大したことのない小技的なことだが、
割と利点は大きかったりすると思うので、使えそうなときは
この記述を検討すると良いかもしれない。

category: C++

TB: --    CM: 0

プロフィール

カレンダー

最新記事

カテゴリ

検索フォーム

ツイッター

GitHub

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。