2017年6月7日 Theolizer®最新版v1.1.0へ対応するために修正しました。
最新版のソース一式をGistに置いてます。

こんにちは。田原です。

データ構造が大きく複雑になってくると全てを同じファイルへ保存するのではなく、保存先を分ける必要が出てくると思います。
例えば、ConfigureファイルやSettingsファイル、Dataファイル等ですね。
また、保存したくない変数もあるでしょう。ファイル・ハンドルとか、一時的なワークエリアなど。
今回はそのような要求に対応できる機能を説明します。

1.保存先指定の使い方

SettingsファイルとDataファイルに分けて保存/回復すること、および、保存しない変数を指定することは下記手順で行います。

  1. 「保存先」を示すシンボルを定義します。
  2. クラスや構造体の各メンバ変数に対してそのシンボルを指定します。
  3. JsonOSerializerなどのシリアライザを使う時に保存先シンボルを指定します。

保存先シンボルをシリアライザへ指定すると、そのシンボルが指定されたメンバ変数が保存/回復されるようになります。
保存先シンボルを指定しない場合は「全て」の意味となり、常に保存/回復されます。
また、「保存しない」という指定もできます。

1-1.「保存先」を示すシンボルを定義します。

まず、全ての保存先指定を行うクラスより前で下記のようなTHEOLIZER_DESTINATIONS()マクロで保存先シンボルを定義します。

01
02
03
04
05
06
THEOLIZER_DESTINATIONS
(
    All,                // 引き継ぎ元保存先定義の最後のシンボル
    Settings,           // 設定情報
    Data                // データ
);

Allは変更不可です。Settings以降を設定できます。

1-2.クラスや構造体の各メンバ変数に対してそのシンボルを指定します。

次に、メンバ変数に保存先を指定するのですが、書式が結構長いのでマクロで短縮定義しましょう。

01
02
03
#define SETTINGS    THEOLIZER_ANNOTATE(FS:<theolizerD::Settings>)
#define DATA        THEOLIZER_ANNOTATE(FS:<theolizerD::Data>)
#define NO_SAVE     THEOLIZER_ANNOTATE(FN)

FSは保存するフィールドでオプションとして保存先シンボルを指定できます。
FNは保存しないフィールドです。(保存しないのですから、保存先は指定できません。)
theolizerD::は実装上の都合によるオマジナイです。

今回はデータ構造自体は前回と同じですので、それに保存先を指定してみます。
科目(Item)は残高をDataファイルへ保存、計算領域のmAssetsIncreaseは保存しない、それ以外のメンバを全てSettingsファイルへ保存するように指定しました。子科目はSettings, Dataファイルの両方へ保存することになるので無指定です。

01
02
03
04
05
06
07
08
09
10
struct Item
{
    Item*                           mParent         SETTINGS;   // 親科目
    std::string                     mName           SETTINGS;   // 科目名
    bool                            mIsAssets       SETTINGS;   // 資産(財布や預金)
    int                             mAssetsIncrease NO_SAVE;    // 増加した資産金額
    bool                            mDoManage       SETTINGS;   // 残高管理の有無
    int                             mAmount         DATA;       // 残高
    theolizer::ListPointee<Item>    mChildren;                  // 子科目
};

そして、取引(Trade)リストは全てDataファイルへ保存するよう指定しました。

01
02
03
04
05
struct HouseholdAccounts
{
    Item                mItemTree  POINTEE; // 科目ツリー
    std::list<Trade>    mTradeList DATA;    // 取引のリスト
};

1-3.JsonOSerializerなどのシリアライザを使う時に保存先シンボルを指定します。

下記のように指定して保存/回復します。

保存

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 保存処理(Settings)
{
    // 保存先のファイルをオープンする
    std::ofstream   aStream(aSettings);
 
    // シリアライザを用意する
    theolizer::JsonOSerializer<theolizerD::Settings>    js(aStream);
 
    // 家計簿をSettings.jsonファイルへ保存する
    THEOLIZER_PROCESS(js, aHouseholdAccountsSave);
 
    // オブジェクト追跡の締め
    js.clearTracking();
}
 
// 保存処理(Data)
{
    // 保存先のファイルをオープンする
    std::ofstream   aStream(aData);
 
    // シリアライザを用意する
    theolizer::JsonOSerializer<theolizerD::Data>    js(aStream);
 
    // 家計簿をData.jsonファイルへ保存する
    THEOLIZER_PROCESS(js, aHouseholdAccountsSave);
 
    // オブジェクト追跡の締め
    js.clearTracking();
}

回復

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 回復処理(Settings)
{
    // 回復元のファイルをオープンする
    std::ifstream   aStream(aSettings);
 
    // シリアライザを用意する
    theolizer::JsonISerializer<theolizerD::Settings>    js(aStream);
 
    // 家計簿をSettings.jsonファイルから回復する
    THEOLIZER_PROCESS(js, aHouseholdAccountsLoad);
 
    // オブジェクト追跡の締め
    js.clearTracking();
}
 
// 回復処理(Data)
{
    // 回復元のファイルをオープンする
    std::ifstream   aStream(aData);
 
    // シリアライザを用意する
    theolizer::JsonISerializer<theolizerD::Data>    js(aStream);
 
    // 家計簿をData.jsonファイルから回復する
    THEOLIZER_PROCESS(js, aHouseholdAccountsLoad);
 
    // オブジェクト追跡の締め
    js.clearTracking();
}

2.今回のソース・コード

前回のソース・コードに対して主に上記変更を行っただけですので、まとめてソースを示します。
保存先を指定しただけで家計簿のメイン処理に影響するような変更をしていませんので、sub.cppはコメント以外何も修正していません。

なお、次回解説するバージョン・アップ/ダウン処理用に2行追加しています。

main.cpp : #define THEOLIZER_GLOBAL_VERSION_TABLE
common.h : THEOLIZER_DEFINE_GLOBAL_VERSION_TABLE(GlobalVersionTable, 1);

これらについては次回説明しますので、今は気にしないで下さい。

2-1.構造体定義

common.h
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//############################################################################
//      Theolizer解説用サンプル・プログラム3
//
//          簡単な家計簿用共通定義
//############################################################################
 
#if !defined(COMMON_H)
#define COMMON_H
 
// ***************************************************************************
//      インクルード
// ***************************************************************************
 
// 標準ライブラリ
#include <string>
 
// Theolizerライブラリ
#include <theolizer/serializer_json.h>
#include <theolizer/list.h>
 
// ***************************************************************************
//      保存先定義
// ***************************************************************************
 
THEOLIZER_DESTINATIONS
(
    All,                // 引き継ぎ元保存先定義の最後のシンボル
    Settings,           // 設定情報
    Data                // データ
);
 
#define SETTINGS    THEOLIZER_ANNOTATE(FS:<theolizerD::Settings>)
#define DATA        THEOLIZER_ANNOTATE(FS:<theolizerD::Data>)
#define NO_SAVE     THEOLIZER_ANNOTATE(FN)
 
// ***************************************************************************
//      グローバル・バージョン番号テーブル
// ***************************************************************************
 
THEOLIZER_DEFINE_GLOBAL_VERSION_TABLE(GlobalVersionTable, 1);
 
// ***************************************************************************
//      構造体定義
// ***************************************************************************
 
#define POINTEE     THEOLIZER_ANNOTATE(FS:<>Pointee)
 
//----------------------------------------------------------------------------
//      科目管理
//----------------------------------------------------------------------------
 
struct Item
{
    Item*                           mParent         SETTINGS;   // 親科目
    std::string                     mName           SETTINGS;   // 科目名
    bool                            mIsAssets       SETTINGS;   // 資産(財布や預金)
    int                             mAssetsIncrease NO_SAVE;    // 増加した資産金額
    bool                            mDoManage       SETTINGS;   // 残高管理の有無
    int                             mAmount         DATA;       // 残高
    theolizer::ListPointee<Item>    mChildren;                  // 子科目
};
 
typedef theolizer::ListPointee<Item>::iterator  ChildIterator;
 
//----------------------------------------------------------------------------
//      取引記録
//----------------------------------------------------------------------------
 
struct Date
{
    short       mYear;                  // 年
    char        mMonth;                 // 月(1-12)
    char        mDay;                   // 日(1-31)
};
 
struct Trade
{
    Date        mDate;                  // 取引日
    Item*       mDebitItem;             // 購入品(借方科目)
    int         mAmount;                // 金額
    Item*       mCreditItem;            // 財布 (貸方科目)
    std::string mNote;                  // 備考
};
 
//----------------------------------------------------------------------------
//      家計簿
//----------------------------------------------------------------------------
 
struct HouseholdAccounts
{
    Item                mItemTree  POINTEE; // 科目ツリー
    std::list<Trade>    mTradeList DATA;    // 取引のリスト
};
 
typedef std::list<Trade>::iterator  TradeIterator;
 
// ***************************************************************************
//      関数群
// ***************************************************************************
 
//----------------------------------------------------------------------------
//      初期設定
//----------------------------------------------------------------------------
 
void initialize(HouseholdAccounts* oHouseholdAccounts);
void display(   HouseholdAccounts* iHouseholdAccounts);
void calculate( HouseholdAccounts* ioHouseholdAccounts);
 
#endif

2-2.データの保存と回復、および、簡単な集計と表示

main.cpp
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//############################################################################
//      Theolizer解説用サンプル・プログラム3
//
//          メイン処理(データ保存/回復サンプル)
//############################################################################
 
#define THEOLIZER_GLOBAL_VERSION_TABLE
 
// ***************************************************************************
//      インクルード
// ***************************************************************************
 
// 標準ライブラリ
#include <iostream>
#include <fstream>
 
// 共通定義
#include "common.h"
 
// Theolizer自動生成先
#include "main.cpp.theolizer.hpp"
 
// ***************************************************************************
//      メイン
// ***************************************************************************
 
int main(int argc, char* argv[])
{
//----------------------------------------------------------------------------
//      バラメータ解析
//----------------------------------------------------------------------------
 
    std::string aSufix="";
    if (1 < argc)
    {
        aSufix=argv[1];
    }
    std::cout << theolizer::print("Sufix=%s\n", aSufix);
 
    std::string aSettings = theolizer::print("Settings%s.json", aSufix).str();
    std::string aData     = theolizer::print("Data%s.json", aSufix).str();
 
//----------------------------------------------------------------------------
//      家計簿設定
//----------------------------------------------------------------------------
 
    // サフィックス指定されたら回復処理のみ実行する
    if (aSufix == "")
    {
        // 保存用家計簿
        HouseholdAccounts   aHouseholdAccountsSave;
 
        // 初期設定(科目と取引データを設定している)
        initialize(&aHouseholdAccountsSave);
 
//----------------------------------------------------------------------------
//      保存
//----------------------------------------------------------------------------
 
        std::cout << u8"<<< 保存するサンプル・データ >>>\n";
        display(&aHouseholdAccountsSave);
 
        // 保存処理(Settings)
        {
            // 保存先のファイルをオープンする
            std::ofstream   aStream(aSettings);
 
            // シリアライザを用意する
            theolizer::JsonOSerializer<theolizerD::Settings>    js(aStream);
 
            // 家計簿をSettings.jsonファイルへ保存する
            THEOLIZER_PROCESS(js, aHouseholdAccountsSave);
 
            // オブジェクト追跡の締め
            js.clearTracking();
        }
 
        // 保存処理(Data)
        {
            // 保存先のファイルをオープンする
            std::ofstream   aStream(aData);
 
            // シリアライザを用意する
            theolizer::JsonOSerializer<theolizerD::Data>    js(aStream);
 
            // 家計簿をData.jsonファイルへ保存する
            THEOLIZER_PROCESS(js, aHouseholdAccountsSave);
 
            // オブジェクト追跡の締め
            js.clearTracking();
        }
    }
 
//----------------------------------------------------------------------------
//      回復
//----------------------------------------------------------------------------
 
    // 回復用家計簿(正確に回復できていることを示すため、保存用と別領域)
    HouseholdAccounts   aHouseholdAccountsLoad;
 
    // 回復処理(Settings)
    {
        // 回復元のファイルをオープンする
        std::ifstream   aStream(aSettings);
 
        // シリアライザを用意する
        theolizer::JsonISerializer<theolizerD::Settings>    js(aStream);
 
        // 家計簿をSettings.jsonファイルから回復する
        THEOLIZER_PROCESS(js, aHouseholdAccountsLoad);
 
        // オブジェクト追跡の締め
        js.clearTracking();
    }
 
    // 回復処理(Data)
    {
        // 回復元のファイルをオープンする
        std::ifstream   aStream(aData);
 
        // シリアライザを用意する
        theolizer::JsonISerializer<theolizerD::Data>    js(aStream);
 
        // 家計簿をData.jsonファイルから回復する
        THEOLIZER_PROCESS(js, aHouseholdAccountsLoad);
 
        // オブジェクト追跡の締め
        js.clearTracking();
    }
 
//----------------------------------------------------------------------------
//      内容表示と簡単な集計処理
//----------------------------------------------------------------------------
 
    std::cout << u8"\n\n<<< 回復したサンプル・データ >>>\n";
    display(&aHouseholdAccountsLoad);
 
    std::cout << u8"\n\n<<< サンプルの集計結果 >>>\n";
    calculate(&aHouseholdAccountsLoad);
 
    return 0;
}

2-3.家計簿アプリケーションのメインに当たる部分

sub.cpp
[cpp] //############################################################################
// Theolizer解説用サンプル・プログラム3(2と同じもの)
//
// 補助関数群(家計簿にサンプル・データ設定/表示)
//############################################################################

// ***************************************************************************
// インクルード
// ***************************************************************************

// 標準ライブラリ
#include <iostream>
#include <fstream>

// 共通定義
#include "common.h"

// ***************************************************************************
// 家計簿にサンプル・データ設定
// ***************************************************************************

//—————————————————————————-
// find 科目
//—————————————————————————-

Item* find(Item* iItem, char const* iItemName)
{
if (iItem->mName == iItemName)
return iItem;

for (ChildIterator itr=iItem->mChildren.begin(); itr != iItem->mChildren.end(); ++itr)
{
Item* ret=find(&(*itr), iItemName);
if (ret)
return ret;
}

return NULL;
}

//—————————————————————————-
// 科目ツリー設定
// 家計
// 収入
// 給料
// 雑収入
// 支出
// 食費
// 主食
// お米
// パン
// 副食
// 肉魚
// 野菜
// 果物
// 現金
// 財布
// 預金
//—————————————————————————-

// —<<< 子科目設定 >>>—

Item* pushItem
(
Item* oItem,
char const* iItemName,
bool iIsAssets=false,
bool iDoManage=false,
int iAmount=0
)
{
Item aItem;
aItem.mParent =oItem;
aItem.mName =iItemName;
aItem.mIsAssets =iIsAssets;
aItem.mAssetsIncrease =0;
aItem.mDoManage =iDoManage;
aItem.mAmount =iAmount;

oItem->mChildren.push_back(aItem);
return &(oItem->mChildren.back());
}

// —<<< 科目ツリー設定 >>>—

void makeItems(Item* oItemTree)
{
oItemTree->mParent =NULL;
oItemTree->mName =u8"家計";
oItemTree->mIsAssets=false;
oItemTree->mDoManage=false;
oItemTree->mAmount =0;

Item* aLayer0=oItemTree;
{
Item* aLayer1;
aLayer1=pushItem(aLayer0, u8"収入");
{
pushItem(aLayer1, u8"給料");
pushItem(aLayer1, u8"雑収入");
}
aLayer1=pushItem(aLayer0, u8"支出");
{
Item* aLayer2;
aLayer2=pushItem(aLayer1, u8"主食");
{
pushItem(aLayer2, u8"お米");
pushItem(aLayer2, u8"パン");
}
aLayer2=pushItem(aLayer1, u8"副食");
{
pushItem(aLayer2, u8"肉魚");
pushItem(aLayer2, u8"野菜");
pushItem(aLayer2, u8"果物");
}
}
aLayer1=pushItem(aLayer0, u8"現金", true);
{
pushItem(aLayer1, u8"財布", true, true, 35592);
pushItem(aLayer1, u8"預金", true, true, 147135);
}
}
}

//—————————————————————————-
// 取引リスト設定
//—————————————————————————-

// —<<< 取引設定サブ >>>—

bool pushTrade
(
HouseholdAccounts* oHA,
short iYear,
char iMonth,
char iDay,
char const* iDebitName,
int iAmount,
char const* iCreditName,
char const* iNote
)
{
Trade aTrade;
aTrade.mDate.mYear = iYear;
aTrade.mDate.mMonth = iMonth;
aTrade.mDate.mDay = iDay;
aTrade.mDebitItem = find(&(oHA->mItemTree), iDebitName);
aTrade.mAmount = iAmount;
aTrade.mCreditItem = find(&(oHA->mItemTree), iCreditName);
aTrade.mNote = iNote;

if (aTrade.mDebitItem == NULL)
{
std::cerr << theolizer::print(u8"商品名(%s)が不正です。", iDebitName) << std::endl;
return false;
}
if (aTrade.mCreditItem == NULL)
{
std::cerr << theolizer::print(u8"商品名(%s)が不正です。", iCreditName) << std::endl;
return false;
}

oHA->mTradeList.push_back(aTrade);
return true;
}

// —<<< 取引リスト設定 >>>—

void makeTrades(HouseholdAccounts* oHA)
{
pushTrade(oHA, 2016, 8,22, u8"パン", 158, u8"財布", u8"六切り1袋");
pushTrade(oHA, 2016, 8,22, u8"肉魚", 269, u8"財布", u8"鶏肉200g");
pushTrade(oHA, 2016, 8,22, u8"野菜", 182, u8"財布", u8"キャベツ1玉");
pushTrade(oHA, 2016, 8,22, u8"果物", 113, u8"財布", u8"バナナ1房");
pushTrade(oHA, 2016, 8,22, u8"預金", 254536, u8"給料", u8"セオライド テクノロジー");
pushTrade(oHA, 2016, 8,25, u8"財布", 50000, u8"預金", u8"生活費");
pushTrade(oHA, 2016, 8,25, u8"お米", 4652, u8"財布", u8"こしひかり10Kg");
pushTrade(oHA, 2016, 8,25, u8"肉魚", 685, u8"財布", u8"豚肉500g");
pushTrade(oHA, 2016, 8,25, u8"野菜", 152, u8"財布", u8"ほうれん草");
pushTrade(oHA, 2016, 8,25, u8"野菜", 136, u8"財布", u8"人参");
}

//—————————————————————————-
// 設定
//—————————————————————————-

void initialize(HouseholdAccounts* oHouseholdAccounts)
{
makeItems(&(oHouseholdAccounts->mItemTree));
makeTrades(oHouseholdAccounts);
}

// ***************************************************************************
// 家計簿表示
// ***************************************************************************

//—————————————————————————-
// 科目名結合
//—————————————————————————-

std::string getFullName(Item* iItem)
{
if (iItem->mParent != NULL)
{
return getFullName(iItem->mParent) + "/" + iItem->mName;
}
else
{
return iItem->mName;
}
}

//—————————————————————————-
// 科目表示
//—————————————————————————-

void displayItems(int iIndent, Item* iItem)
{
std::cout << std::string(iIndent*2, ‘ ‘) << iItem->mName;
if (iItem->mDoManage)
{
std::cout << u8" 残高:" << iItem->mAmount;
}
std::cout << "\n";
for (ChildIterator itr=iItem->mChildren.begin(); itr != iItem->mChildren.end(); ++itr)
{
displayItems(iIndent+1, &(*itr));
}
}

//—————————————————————————-
// 取引表示
//—————————————————————————-

void displayTrades(HouseholdAccounts* iHA)
{
for (TradeIterator itr=iHA->mTradeList.begin(); itr != iHA->mTradeList.end(); ++itr)
{
std::cout << theolizer::print("%04d/%02d/%02d %s <- %s(%6d) : %s\n",
itr->mDate.mYear,
itr->mDate.mMonth+0,
itr->mDate.mDay+0,
getFullName(itr->mDebitItem),
getFullName(itr->mCreditItem),
itr->mAmount,
itr->mNote);
}
}

//—————————————————————————-
// 全体表示
//—————————————————————————-

void display(HouseholdAccounts* iHouseholdAccounts)
{
std::cout << u8"— 科目 —\n";
displayItems(0, &(iHouseholdAccounts->mItemTree));

std::cout << u8"\n— 取引 —\n";
displayTrades(iHouseholdAccounts);
}

// ***************************************************************************
// 家計簿処理と結果表示
// ***************************************************************************

//—————————————————————————-
// 初期化
//—————————————————————————-

void clearIncrease(Item* iItem)
{
iItem->mAssetsIncrease=0;
for (ChildIterator itr=iItem->mChildren.begin(); itr != iItem->mChildren.end(); ++itr)
{
clearIncrease(&(*itr));
}
}

//—————————————————————————-
// 結果表示
//—————————————————————————-

void displayAmount(Item* iItem)
{
std::cout << getFullName(iItem);
if (iItem->mIsAssets)
{
if (0 <= iItem->mAssetsIncrease)
{
std::cout << theolizer::print(u8" : %6d円の増加", iItem->mAssetsIncrease);
}
else
{
std::cout << theolizer::print(u8" : %6d円の減少", -iItem->mAssetsIncrease);
}
}
else
{
if (0 <= iItem->mAssetsIncrease)
{
std::cout << theolizer::print(u8" : %6d円の収入", iItem->mAssetsIncrease);
}
else
{
std::cout << theolizer::print(u8" : %6d円の消費", -iItem->mAssetsIncrease);
}
}

if (iItem->mDoManage)
{
std::cout << theolizer::print(u8" 残高は%6d円\n", iItem->mAmount);
}
else
{
std::cout << "\n";
}
for (ChildIterator itr=iItem->mChildren.begin(); itr != iItem->mChildren.end(); ++itr)
{
displayAmount(&(*itr));
}
}

//—————————————————————————-
// 計算
//—————————————————————————-

void calculate(HouseholdAccounts* ioHouseholdAccounts)
{
// 初期化
clearIncrease(&(ioHouseholdAccounts->mItemTree));

// 集計
for (TradeIterator itr=ioHouseholdAccounts->mTradeList.begin();
itr != ioHouseholdAccounts->mTradeList.end();
++itr)
{
// —<<< 増減処理 >>>—

// 借方の資産は増える/借方の非資産は減る
for (Item* p=itr->mDebitItem; p != NULL; p=p->mParent)
{
if (p->mIsAssets)
{
p->mAssetsIncrease += itr->mAmount;
}
else
{
p->mAssetsIncrease -= itr->mAmount;
}
}

// 貸方の資産は減る/借方の非資産は増える
for (Item* p=itr->mCreditItem; p != NULL; p=p->mParent)
{
if (p->mIsAssets)
{
p->mAssetsIncrease -= itr->mAmount;
}
else
{
p->mAssetsIncrease += itr->mAmount;
}
}

// —<<< 残高処理 >>>—

// 借方
if (itr->mDebitItem->mDoManage)
{
itr->mDebitItem->mAmount += itr->mAmount;
}

// 貸方
if (itr->mCreditItem->mDoManage)
{
itr->mCreditItem->mAmount -= itr->mAmount;
}
}

displayAmount(&(ioHouseholdAccounts->mItemTree));

}
[/cpp]

2-4.自動生成されたソース

main.cpp.theolizer.hpp
[cpp] #ifdef THEOLIZER_WRITE_CODE // ###### Item ######

#define THEOLIZER_GENERATED_LAST_VERSION_NO THEOLIZER_INTERNAL_DEFINE(kLastVersionNo,1)
#define THEOLIZER_GENERATED_FULL_AUTO Item

// —<<< Version.1 >>>—

#define THEOLIZER_GENERATED_VERSION_NO THEOLIZER_INTERNAL_DEFINE(kVersionNo,1)
#define THEOLIZER_GENERATED_CLASS_NAME()\
THEOLIZER_INTERNAL_CLASS_NAME((u8"Item"))
#define THEOLIZER_GENERATED_ELEMENT_MAP emName
#define THEOLIZER_GENERATED_ELEMENT_LIST()\
THEOLIZER_INTERNAL_ELEMENT_N((mParent),mParent,etmDefault,\
(theolizerD::Settings),\
(Item *))\
THEOLIZER_INTERNAL_ELEMENT_N((mName),mName,etmDefault,\
(theolizerD::Settings),\
(std::string))\
THEOLIZER_INTERNAL_ELEMENT_N((mIsAssets),mIsAssets,etmDefault,\
(theolizerD::Settings),\
(bool))\
THEOLIZER_INTERNAL_ELEMENT_N((mDoManage),mDoManage,etmDefault,\
(theolizerD::Settings),\
(bool))\
THEOLIZER_INTERNAL_ELEMENT_N((mAmount),mAmount,etmDefault,\
(theolizerD::Data),\
(int))\
THEOLIZER_INTERNAL_ELEMENT_N((mChildren),mChildren,etmDefault,\
(theolizerD::All),\
(theolizer::ListPointee<Item>))
#include <theolizer/internal/version_auto.inc>
#undef THEOLIZER_GENERATED_VERSION_NO

#endif//THEOLIZER_WRITE_CODE // ###### Item ######

#ifdef THEOLIZER_WRITE_CODE // ###### Date ######

#define THEOLIZER_GENERATED_LAST_VERSION_NO THEOLIZER_INTERNAL_DEFINE(kLastVersionNo,1)
#define THEOLIZER_GENERATED_FULL_AUTO Date

// —<<< Version.1 >>>—

#define THEOLIZER_GENERATED_VERSION_NO THEOLIZER_INTERNAL_DEFINE(kVersionNo,1)
#define THEOLIZER_GENERATED_CLASS_NAME()\
THEOLIZER_INTERNAL_CLASS_NAME((u8"Date"))
#define THEOLIZER_GENERATED_ELEMENT_MAP emName
#define THEOLIZER_GENERATED_ELEMENT_LIST()\
THEOLIZER_INTERNAL_ELEMENT_N((mYear),mYear,etmDefault,\
(theolizerD::All),\
(short))\
THEOLIZER_INTERNAL_ELEMENT_N((mMonth),mMonth,etmDefault,\
(theolizerD::All),\
(char))\
THEOLIZER_INTERNAL_ELEMENT_N((mDay),mDay,etmDefault,\
(theolizerD::All),\
(char))
#include <theolizer/internal/version_auto.inc>
#undef THEOLIZER_GENERATED_VERSION_NO

#endif//THEOLIZER_WRITE_CODE // ###### Date ######

#ifdef THEOLIZER_WRITE_CODE // ###### Trade ######

#define THEOLIZER_GENERATED_LAST_VERSION_NO THEOLIZER_INTERNAL_DEFINE(kLastVersionNo,1)
#define THEOLIZER_GENERATED_FULL_AUTO Trade

// —<<< Version.1 >>>—

#define THEOLIZER_GENERATED_VERSION_NO THEOLIZER_INTERNAL_DEFINE(kVersionNo,1)
#define THEOLIZER_GENERATED_CLASS_NAME()\
THEOLIZER_INTERNAL_CLASS_NAME((u8"Trade"))
#define THEOLIZER_GENERATED_ELEMENT_MAP emName
#define THEOLIZER_GENERATED_ELEMENT_LIST()\
THEOLIZER_INTERNAL_ELEMENT_KN((mDate),mDate,etmDefault,\
(theolizerD::All),\
(Date),1)\
THEOLIZER_INTERNAL_ELEMENT_N((mDebitItem),mDebitItem,etmDefault,\
(theolizerD::All),\
(Item *))\
THEOLIZER_INTERNAL_ELEMENT_N((mAmount),mAmount,etmDefault,\
(theolizerD::All),\
(int))\
THEOLIZER_INTERNAL_ELEMENT_N((mCreditItem),mCreditItem,etmDefault,\
(theolizerD::All),\
(Item *))\
THEOLIZER_INTERNAL_ELEMENT_N((mNote),mNote,etmDefault,\
(theolizerD::All),\
(std::string))
#include <theolizer/internal/version_auto.inc>
#undef THEOLIZER_GENERATED_VERSION_NO

#endif//THEOLIZER_WRITE_CODE // ###### Trade ######

#ifdef THEOLIZER_WRITE_CODE // ###### HouseholdAccounts ######

#define THEOLIZER_GENERATED_LAST_VERSION_NO THEOLIZER_INTERNAL_DEFINE(kLastVersionNo,1)
#define THEOLIZER_GENERATED_FULL_AUTO HouseholdAccounts

// —<<< Version.1 >>>—

#define THEOLIZER_GENERATED_VERSION_NO THEOLIZER_INTERNAL_DEFINE(kVersionNo,1)
#define THEOLIZER_GENERATED_CLASS_NAME()\
THEOLIZER_INTERNAL_CLASS_NAME((u8"HouseholdAccounts"))
#define THEOLIZER_GENERATED_ELEMENT_MAP emName
#define THEOLIZER_GENERATED_ELEMENT_LIST()\
THEOLIZER_INTERNAL_ELEMENT_KN((mItemTree),mItemTree,etmPointee,\
(theolizerD::All),\
(Item),1)\
THEOLIZER_INTERNAL_ELEMENT_N((mTradeList),mTradeList,etmDefault,\
(theolizerD::Data),\
(std::list<Trade>))
#include <theolizer/internal/version_auto.inc>
#undef THEOLIZER_GENERATED_VERSION_NO

#endif//THEOLIZER_WRITE_CODE // ###### HouseholdAccounts ######

#ifdef THEOLIZER_WRITE_CODE // ###### Global VersionNo. Table ######

namespace theolizer{namespace internal{
namespace global_table{
GlobalVersionTable::GlobalVersionTable()
{
THEOLIZER_INTERNAL_ADD(theolizer::internal::JsonMidOSerializer,1u);
THEOLIZER_INTERNAL_ADD(theolizer::internal::JsonMidISerializer,1u);
THEOLIZER_INTERNAL_ADD(pairTheolizer,1u);
THEOLIZER_INTERNAL_ADD(listTheolizer,1u);
THEOLIZER_INTERNAL_ADD(ListPointeeTheolizer,1u);
}
} // namespace global_table
}} // namespace theolizer

#endif//THEOLIZER_WRITE_CODE // ###### Global VersionNo. Table ######
[/cpp]

3.実行結果

3-1.標準出力

result.log
[text] Sufix=
<<< 保存するサンプル・データ >>>
— 科目 —
家計
収入
給料
雑収入
支出
主食
お米
パン
副食
肉魚
野菜
果物
現金
財布 残高:35592
預金 残高:147135

— 取引 —
2016/08/22 家計/支出/主食/パン <- 家計/現金/財布( 158) : 六切り1袋
2016/08/22 家計/支出/副食/肉魚 <- 家計/現金/財布( 269) : 鶏肉200g
2016/08/22 家計/支出/副食/野菜 <- 家計/現金/財布( 182) : キャベツ1玉
2016/08/22 家計/支出/副食/果物 <- 家計/現金/財布( 113) : バナナ1房
2016/08/22 家計/現金/預金 <- 家計/収入/給料(254536) : セオライド テクノロジー
2016/08/25 家計/現金/財布 <- 家計/現金/預金( 50000) : 生活費
2016/08/25 家計/支出/主食/お米 <- 家計/現金/財布( 4652) : こしひかり10Kg
2016/08/25 家計/支出/副食/肉魚 <- 家計/現金/財布( 685) : 豚肉500g
2016/08/25 家計/支出/副食/野菜 <- 家計/現金/財布( 152) : ほうれん草
2016/08/25 家計/支出/副食/野菜 <- 家計/現金/財布( 136) : 人参

<<< 回復したサンプル・データ >>>
— 科目 —
家計
収入
給料
雑収入
支出
主食
お米
パン
副食
肉魚
野菜
果物
現金
財布 残高:35592
預金 残高:147135

— 取引 —
2016/08/22 家計/支出/主食/パン <- 家計/現金/財布( 158) : 六切り1袋
2016/08/22 家計/支出/副食/肉魚 <- 家計/現金/財布( 269) : 鶏肉200g
2016/08/22 家計/支出/副食/野菜 <- 家計/現金/財布( 182) : キャベツ1玉
2016/08/22 家計/支出/副食/果物 <- 家計/現金/財布( 113) : バナナ1房
2016/08/22 家計/現金/預金 <- 家計/収入/給料(254536) : セオライド テクノロジー
2016/08/25 家計/現金/財布 <- 家計/現金/預金( 50000) : 生活費
2016/08/25 家計/支出/主食/お米 <- 家計/現金/財布( 4652) : こしひかり10Kg
2016/08/25 家計/支出/副食/肉魚 <- 家計/現金/財布( 685) : 豚肉500g
2016/08/25 家計/支出/副食/野菜 <- 家計/現金/財布( 152) : ほうれん草
2016/08/25 家計/支出/副食/野菜 <- 家計/現金/財布( 136) : 人参

<<< サンプルの集計結果 >>>
家計 : 0円の収入
家計/収入 : 254536円の収入
家計/収入/給料 : 254536円の収入
家計/収入/雑収入 : 0円の収入
家計/支出 : 6347円の消費
家計/支出/主食 : 4810円の消費
家計/支出/主食/お米 : 4652円の消費
家計/支出/主食/パン : 158円の消費
家計/支出/副食 : 1537円の消費
家計/支出/副食/肉魚 : 954円の消費
家計/支出/副食/野菜 : 470円の消費
家計/支出/副食/果物 : 113円の消費
家計/現金 : 248189円の増加
家計/現金/財布 : 43653円の増加 残高は 79245円
家計/現金/預金 : 204536円の増加 残高は351671円
[/text]

2-5.CMakeLists.txt

CMakeLists.txt
[text] #[[###########################################################################
Theolizer紹介用サンプルCMakeLists.txt
]]############################################################################

if("${CMAKE_VERSION}" STREQUAL "")
set(CMAKE_VERSION, 3.5.0)
endif()
cmake_minimum_required(VERSION ${CMAKE_VERSION})

message(STATUS "BOOST_ROOT=${BOOST_ROOT}")

#—————————————————————————–
# プロジェクト設定
#—————————————————————————–

set(TARGET_NAME sample)
set(SOURCE_LIST main.cpp sub.cpp)
set(HEADER_LIST common.h)

project(${TARGET_NAME} VERSION 1.0.0)

#—————————————————————————–
# ビルド設定
#—————————————————————————–

# MSVCの通常使わないビルド・モードとZERO_CHECKプロジェクトの削除
set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Configs" FORCE)
set(CMAKE_SUPPRESS_REGENERATION TRUE)

# Theolizer
find_package(THEOLIZER)

# Options
if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC)
add_definitions(-D_UNICODE -DUNICODE)
set(CMAKE_DEBUG_POSTFIX "d")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

# MinGWの不具合(https://sourceforge.net/p/mingw-w64/discussion/723797/thread/c6b70624/#7f0a)暫定対処
if((CMAKE_COMPILER_IS_MINGW) AND (CMAKE_SIZEOF_VOID_P EQUAL 8))
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wa,-mbig-obj")
endif()
endif()

# example
add_executable(${TARGET_NAME} ${SOURCE_LIST} ${HEADER_LIST})
setup_theolizer(${TARGET_NAME} StaticWithBoost)

#—————————————————————————–
# テスト実行
#—————————————————————————–

enable_testing()
add_test(NAME ${TARGET_NAME} COMMAND $<TARGET_FILE:${TARGET_NAME}>)

add_custom_target(BuildTest COMMAND "ctest" "-V" "-C" $<CONFIG>)
add_dependencies(BuildTest ${TARGET_NAME})
[/text]

3-2.Theolzierにて保存された設定ファイル

Settings.json
{
“SerialzierName”:”JsonTheolizer”,
“GlobalVersionNo”:1,
“TypeInfoList”:[1] }
{
“mItemTree”:[1,{
“mParent”:0,
“mName”:”家計”,
“mIsAssets”:0,
“mDoManage”:0,
“mChildren”:[
3,
[2,{
“mParent”:1,
“mName”:”収入”,
“mIsAssets”:0,
“mDoManage”:0,
“mChildren”:[
2,
[3,{
“mParent”:2,
“mName”:”給料”,
“mIsAssets”:0,
“mDoManage”:0,
“mChildren”:[
0
] }],
[4,{
“mParent”:2,
“mName”:”雑収入”,
“mIsAssets”:0,
“mDoManage”:0,
“mChildren”:[
0
] }] ] }],
[5,{
“mParent”:1,
“mName”:”支出”,
“mIsAssets”:0,
“mDoManage”:0,
“mChildren”:[
2,
[6,{
“mParent”:5,
“mName”:”主食”,
“mIsAssets”:0,
“mDoManage”:0,
“mChildren”:[
2,
[7,{
“mParent”:6,
“mName”:”お米”,
“mIsAssets”:0,
“mDoManage”:0,
“mChildren”:[
0
] }],
[8,{
“mParent”:6,
“mName”:”パン”,
“mIsAssets”:0,
“mDoManage”:0,
“mChildren”:[
0
] }] ] }],
[9,{
“mParent”:5,
“mName”:”副食”,
“mIsAssets”:0,
“mDoManage”:0,
“mChildren”:[
3,
[10,{
“mParent”:9,
“mName”:”肉魚”,
“mIsAssets”:0,
“mDoManage”:0,
“mChildren”:[
0
] }],
[11,{
“mParent”:9,
“mName”:”野菜”,
“mIsAssets”:0,
“mDoManage”:0,
“mChildren”:[
0
] }],
[12,{
“mParent”:9,
“mName”:”果物”,
“mIsAssets”:0,
“mDoManage”:0,
“mChildren”:[
0
] }] ] }] ] }],
[13,{
“mParent”:1,
“mName”:”現金”,
“mIsAssets”:1,
“mDoManage”:0,
“mChildren”:[
2,
[14,{
“mParent”:13,
“mName”:”財布”,
“mIsAssets”:1,
“mDoManage”:1,
“mChildren”:[
0
] }],
[15,{
“mParent”:13,
“mName”:”預金”,
“mIsAssets”:1,
“mDoManage”:1,
“mChildren”:[
0
] }] ] }] ] }] }

3-3.Theolzierにて保存されたデータファイル

Data.json
{
“SerialzierName”:”JsonTheolizer”,
“GlobalVersionNo”:1,
“TypeInfoList”:[1] }
{
“mItemTree”:[1,{
“mAmount”:0,
“mChildren”:[
3,
[2,{
“mAmount”:0,
“mChildren”:[
2,
[3,{
“mAmount”:0,
“mChildren”:[
0
] }],
[4,{
“mAmount”:0,
“mChildren”:[
0
] }] ] }],
[5,{
“mAmount”:0,
“mChildren”:[
2,
[6,{
“mAmount”:0,
“mChildren”:[
2,
[7,{
“mAmount”:0,
“mChildren”:[
0
] }],
[8,{
“mAmount”:0,
“mChildren”:[
0
] }] ] }],
[9,{
“mAmount”:0,
“mChildren”:[
3,
[10,{
“mAmount”:0,
“mChildren”:[
0
] }],
[11,{
“mAmount”:0,
“mChildren”:[
0
] }],
[12,{
“mAmount”:0,
“mChildren”:[
0
] }] ] }] ] }],
[13,{
“mAmount”:0,
“mChildren”:[
2,
[14,{
“mAmount”:35592,
“mChildren”:[
0
] }],
[15,{
“mAmount”:147135,
“mChildren”:[
0
] }] ] }] ] }],
“mTradeList”:[
10,
{
“mDate”:{
“mYear”:2016,
“mMonth”:8,
“mDay”:22
},
“mDebitItem”:8,
“mAmount”:158,
“mCreditItem”:14,
“mNote”:”六切り1袋”
},
{
“mDate”:{
“mYear”:2016,
“mMonth”:8,
“mDay”:22
},
“mDebitItem”:10,
“mAmount”:269,
“mCreditItem”:14,
“mNote”:”鶏肉200g”
},
{
“mDate”:{
“mYear”:2016,
“mMonth”:8,
“mDay”:22
},
“mDebitItem”:11,
“mAmount”:182,
“mCreditItem”:14,
“mNote”:”キャベツ1玉”
},
{
“mDate”:{
“mYear”:2016,
“mMonth”:8,
“mDay”:22
},
“mDebitItem”:12,
“mAmount”:113,
“mCreditItem”:14,
“mNote”:”バナナ1房”
},
{
“mDate”:{
“mYear”:2016,
“mMonth”:8,
“mDay”:22
},
“mDebitItem”:15,
“mAmount”:254536,
“mCreditItem”:3,
“mNote”:”セオライド テクノロジー”
},
{
“mDate”:{
“mYear”:2016,
“mMonth”:8,
“mDay”:25
},
“mDebitItem”:14,
“mAmount”:50000,
“mCreditItem”:15,
“mNote”:”生活費”
},
{
“mDate”:{
“mYear”:2016,
“mMonth”:8,
“mDay”:25
},
“mDebitItem”:7,
“mAmount”:4652,
“mCreditItem”:14,
“mNote”:”こしひかり10Kg”
},
{
“mDate”:{
“mYear”:2016,
“mMonth”:8,
“mDay”:25
},
“mDebitItem”:10,
“mAmount”:685,
“mCreditItem”:14,
“mNote”:”豚肉500g”
},
{
“mDate”:{
“mYear”:2016,
“mMonth”:8,
“mDay”:25
},
“mDebitItem”:11,
“mAmount”:152,
“mCreditItem”:14,
“mNote”:”ほうれん草”
},
{
“mDate”:{
“mYear”:2016,
“mMonth”:8,
“mDay”:25
},
“mDebitItem”:11,
“mAmount”:136,
“mCreditItem”:14,
“mNote”:”人参”
}
] }

4.解説

科目(Item)は「葉」に当たる構造体のメンバ、および、取引(Trade)リストはに保存先を指定しました。
「葉」より上位の構造体(mItemTree)には保存先を指定していません。ということは「全て」に保存します。
従って、科目(Item)は、指定に従って分割されSettingsファイルとDataファイルの両方へ保存されます。
逆にmTradeListは大元で保存先を指定し、下位の部分では指定していません。大元でDataファイル指定しているため、Settingsファイルへ保存に行きません。そのため、下位の部分で「全て」になっていてもSettingsファイルへは保存されません。

5.まとめ

保存先指定は意外に便利に使えます。まずは保存/回復先のファイルを指定するために使いましたが、例えば取引(Trade)を他のPCから送って貰って処理するような使い方もできます。

次回はバージョン・アップ/ダウン機能を紹介します。乞うご期待。