Life, Education, Death

プログラミング以外でも思ったことをつらつらと書きたい

C++ではじめるテンプレートエンジン入門

ClearSilverとは

ClearSilverC++で使えるテンプレートエンジンで

HDFと呼ばれるデータをテンプレートファイルに注入する仕組みになっている。HDFはテキストとしても表現できるが、プログラムのコードとしても表現できるようになっており柔軟に対応が出来る。

テンプレートには変数を埋め込むだけではなく、ifやforにあたる制御文等もあるので、複雑なデータを出力することも簡単に出来る仕様になっている。


ClearSilverYahoo! GroupsやGoogle Groupsでも使われている。一番身近な利用例はtracかも。
また、C以外の言語でも使えるように各種バインディングが存在する


Linuxユーザーなら公式HPからソースを落としてきてビルドすればいいようだけど、WindowsでVCでビルドしたい人には敷居が高い

VCで使う

調べた結果ここによれば、

cs_config.h を偽造
unistd.h の関数を偽造
__PRETTY_FUNCTION__ を FUNCTION に置換

とかしてみればことがわかり、ここからunistd.hを取ってきてやってみたものの、挫折。
皆さん頑張ってVCで通るようにするのはやめましょう。


http://www.void.in/wiki/ClearSilverでバイナリを配布しているのでこれを利用させてもらいましょう。

使ってみる

公式ページの解説をしているここやテンプレートで使える関数の解説をしているここがとても参考になった。


最後に、バイナリに添付されているソースをベースに外部のHDFファイルを読み込んでCSファイルをコンソールに出力するコードを書いてみた。

HDFファイル
include = #include <math.h>
enum {
	0 {
		name = Test1
		value = 1
	}
	3 {
		name = Test2
		value = 3
	}
	2 {
		name = Test5
		value = 10
	}
}
CSファイル
<?cs var:include ?>

enum HOGE
{
<?cs each:element = enum ?>
	<?cs var:element.name ?> = <?cs var:element.value ?>,<?cs /each ?>
};
ソースファイル
#include <iostream>
#include <fstream>
#include <string>
#include "../include/ClearSilver.h"

NEOERR* csout(void* ctx, char* data)
{
    NEO_STRING* str = (NEO_STRING*)ctx;
    return string_append(str, data);
}

int main(int argc, char* argv[])
{
    nerr_init();

    std::ifstream ifs( "test.hdf" );
    if( ifs.fail() )
    	return -1;

    std::string temp;
    std::string hdfText;
    while( !ifs.eof() )
    {
    	std::getline( ifs, temp );
    	hdfText += temp;
    	hdfText += '\n';
    }
    HDF* hdf = 0;
    hdf_init(&hdf);
    hdf_set_value( hdf, "include", "#include <math>" );
    hdf_set_value( hdf, "enum.0.name", "name1" );
    hdf_set_value( hdf, "enum.0.value", "100" );
    hdf_set_value( hdf, "enum.1.name", "name2" );
    hdf_set_value( hdf, "enum.1.value", "200" );
    hdf_read_string( hdf, hdfText.c_str() );

    NEO_STRING str;
    string_init(&str);
    string_clear(&str);

    CSPARSE* cs = NULL;
    cs_init(&cs, hdf);
    cs_parse_file(cs, "test.cs");

    cs_render(cs, &str, &csout);
    std::cout << str.buf;
    string_clear(&str);

    cs_destroy(&cs);
    hdf_destroy(&hdf);

    return 0;
}
出力
#include <math.h>

enum HOGE
{

        Test1 = 1,
        name2 = 200,
        Test2 = 3,
        Test5 = 10,
};

まとめ

データからソースコードが生成出来て便利。Webじゃないところでも便利なので、ぜひぜひC++畑の人もテンプレートエンジンを使って欲しいなぁと思います。


CSファイルのeachの終了タグの前に改行を入れると、出力結果にも改行が入ってしまう。テンプレートファイルの記述にはちょっと注意したほうがいい。

C++のラッパーもあるようなので、そっちのほうもそのうち試してみたい。