並ゲームプログラマの書き捨て場

ゲームプログラマやってる私の日記、雑記、備忘録、公開場所

非constexprでcount_of

羊が一匹、羊が二匹・・・六万五千五百三十五匹、零匹・・・眠れない!djannです。

depotというヘッダ提供のテンプレートライブラリを現在、Mercurialリポジトリとして公開しているわけなのだが、git用のリポジトリを別で作成した。こちらはヘッダのみが置いてある、言うなれば使用用のリポジトリとなる。Mercurialよりgitの方がユーザが多いので、そちらで公開することにした。リポジトリはこちら


さて、Visual Studioユーザだとconstexprが使用できるようになるのが2015からということで、depotの中で

#define constexpr

という形で何もしないように定義している。だが結果として、constexpr指定がなされているのに定数として使えないということになる。

これは望ましくないことなので、流石に全ては無理だとしても、例えば配列の要素数を戻すようなものをworkaroundで用意しようかと思っていることが若干、現在の悩みどころである。


さて、本気かどうかわからないのだが、count_ofをstatic_assertつまり定数式に使う方法を寄越せ!ただしconstexprは使用不可の環境でだ。clangやgccは使えない。という連絡が来た。

constexprがないcount_ofをそのまま使うことは出来ないので、ではどのように変数名から配列の要素数を取り出し設定しようかと思ったが、そうなると私にはもう一つしか方法が思い浮かばなかった。幸い完全にC++03でとは言われていない。もちろんsizeof(x) / sizeof(x[0])は定数式になるのだが、流石にこれを看破してしまうとポインタを間違って渡した際に想像もしない挙動になってしまうのでよろしくない。

というわけで、C++11になるまではコンパイル時と言えばこれ。だったテンプレートとC++11で地味に使える機能であるdecltypeを用いることにする。テンプレートの特殊化等に関する基礎練習に向いているので、作ったことがないのなら一旦試してみるのもよいかもしれない。知っているならアーハイハイと流すくらいで丁度良い。



#include <iostream>

template <class vType>
struct count_of;		// dummy.
template <class vType, std::size_t N>
struct count_of<vType[N]> {	// specialize for array.
	enum { value = N };
};

int main()
{
	int a[32];
	static_assert( count_of<decltype(a)>::value < 32, "Compile error!!");
}


まあこんなところだろう。思ったのだが、decltypeが無かったら定数式に使える型安全count_ofは果たして実装出来るのだろうか?私は出来る方法が思いつかない。C++03で実装する方法を知っているという方がいれば、是非教えてほしい。


なお

template <class vType, std::size_t N>
constexpr std::size_t count_of( vType (&)[N] ){ return N; }

と同じ使い勝手にする際は悪のdefineに力を借りて

// 上記テンプレートとは違う名前で.
#define countof(x) count_of<decltype(x)>::value

とすれば無問題・・・なのか?constexprが使える環境になった際はこのマクロをお役御免にしてしまえば、記述は変わらず内容が関数に変更される。他の違いはない・・・のかな?

追記

名無し

VC++の_countofマクロをご存じない?

とのコメントを頂いた。
前に見た時にはその実装はsizeof(foo) / sizeof(foo[0])だったような気がしていたのだが、今回Visual Studio 2012から定義をたどっていくとずいぶん違うものであった。

template <typename _CountofType, size_t _SizeOfArray>
char (*__countof_helper(_UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray];
#define _countof(_Array) (sizeof(*__countof_helper(_Array)) + 0)

ひとまずテンプレートを除いて適当な型と数値を割り当てて__countof_helperを記述してみると

char (*__countof_helper( int (&_Arg)[ 10 ] ))[ 10 ];

というような形になる。見慣れない構文にも程があるが、配列char[10]のポインタを戻す関数を定義している、ということだろう。元来から配列のやり取りをするのは非常に奇怪な構文が必要となるC++言語であり、引数部分でも「配列の参照を受け取る」形はこのようになっている。似たようなものだ。そしてそれを呼び出した結果の型をsizeofへ与えている。関数で戻せる型はどのようなものか、呼び出した結果はどのようになるのかを知った方が吸収しやすいと思われるので、そこを踏まえ例を書いた。

int (*fff())[3]{
	static int a[3] = { 0, 1, 2 };
	int (*ret)[3] = &a;	// 長さ3のint型の配列へのポインタを受け取り.
	return ret;	// そして戻す.
}

int main()
{
	// int (*a)[3]と同義である.
	auto a = fff();
	for ( int i = 0; i < 3; ++i ){
		// 0, 1, 2が出力される.
		std::cout << (*a)[i] << std::endl;
	}
	// int *bとなるようだ.
	auto b = *fff();
	for ( int i = 0; i < 3; ++i ){
		// 0, 1, 2が出力される.
		std::cout << b[i] << std::endl;
	}
	// int (*c)[3]となる.
	decltype(fff()) c = fff();
	for ( int i = 0; i < 3; ++i ){
		// 0, 1, 2が出力される.
		std::cout << (*c)[i] << std::endl;
	}
	// int (&d)[3]が結論だ.
	decltype(*fff()) d = *fff();
	for ( int i = 0; i < 3; ++i ){
		// 0, 1, 2が出力される.
		std::cout << d[i] << std::endl;
	}
}

最後のint (&d)[3]となっているところが、_countofマクロ中でsizeofに与えられている型と同様になる。配列の参照をsizeofに渡すことで、配列のサイズが取得できる。__countof_helperはテンプレートであり、引数に与えられた配列の型、要素数が推論される。そしてその推論で導き出された要素数分のchar型配列の参照を戻す。char型は1Byteなので、よってsizeof == countofとなり渡された配列の要素数が取得出来るというカラクリだ。

ポインタにするより、参照を戻す関数*1にした方が、扱いとしてはなじみやすいと思うのだが、そこを配列のポインタを戻す形にしているのは、何かわからない深い意味があってのことなのだろうから、何も言わないようにしておこう。


このカラクリより、関数の呼び出し結果の型をsizeofにコンパイルタイムで渡せるということが、意外とショックを受けた。ならばテンプレート引数にも型として渡せれば、かなり便利だったのに・・・(decltype()はSFINAEとの兼ね合いでVisual Studio上ですこぶる使いづらい。今となってはそれが直ってくれれば良いだけではあるが・・・)。

*1:char (& __countof_helper(...) )[ N ]

しょうもない個人的騒動の話【C++】

So... Do you know? Visual Studio is defective compiler. Because very many bugs exist.
・・・djannです。

英語なんて分からないので、適当に書いている。英語が得意な人は、ぜひ教えてくれると嬉しい。


初っ端からVisual Studioの事をディスってしまっているが、それはあくまでC++に関しての事だけで、単純な開発環境としては割と評価しているので誤解しないでほしい。ただC++C++じゃないというだけの話である。

さて、ではそのC++の部分でどのような騒動に遭遇し「そう・・・どうしようか」となったのかを書いていこう。なお、この記事のターゲットは、現在仕事でメインに使うことになっているVisual Studio 2012となる。そしてここに書いた事は、多分もう大体周知の事実となっていることだろう。

C++11対応の貧弱さ。

 これはもう、言わずもがなと言ったところだろう。一体いくつのworkaroundを仕込んだか分からない。やりたい事を簡単に実現する為の下準備中、当たり前のように書いたコードが当たり前のようにエラーになってくれる悲しみは何とも言い難い。

よもやマクロ展開をループ(再帰)させるコードを私が書くことになるとは思いもよらなかった。可変長引数テンプレートが恋しい。

またconversion to unspecified bool idiomをこの時代になって一々書くとも思っていなかった。explicitの一文が中々どうして、大きな影響を与えてくれていた。

何気に困ったのが、関数テンプレートへのデフォルト引数が存在しない事でもあった。普通に初期値として使うだけでなくSFINAEに便利に使わせてもらっていた。

他キーワードとしてconstexprは空欄へ、noexceptはtrue, falseを受け取れない形でthrow()へ置き換えられるよう定義、alignas(x)は__declspec(align(x))へ、alignof(x)は__alignof(x)へと置き換えた。
が、alignasやalignofはVisual Studioの拡張である__declspec等がテンプレート引数や変数をそのまま受け取ってくれなかったので、そのまま代用とはならなかった。

正しい関数が呼ばれないバグ

 明確にバグだ!と断定できるほどC++の規格に詳しい訳ではないが、若干おかしい挙動を示してくれるコードが存在した。以下のコードを見てほしい。

#include <iostream>


struct foo {
	int x;
	foo() : x( 10 ){
		std::cout << "def constructor : " << x << std::endl;
	}
	template <class vType>
	foo( vType other ){
		std::cout << "constructor ";
		std::cout << "this is " << this << std::endl;
		std::cout << "x is " << x << std::endl;
		x = 20;
	}
	template <class vType>
	foo &operator = ( vType rhs ){
		std::cout << "operator ";
		std::cout << "this is " << this << std::endl;
		std::cout << "x is " << x << std::endl;
		x = 30;
		return *this;
	}
};

void func(){}

int main(){
	foo f;
	f = func;
	f = func;

	std::cout << "f.x is " << f.x << std::endl;
}

このコードの出力はどうなると思うだろうか?私が最初に予想したのはこうだった。アドレスは適当だ。

def constructor : 10
operator this is 0074FBAC
x is 10
operator this is 0074FBAC
x is 30
f.x is 30

だが、Visual Studio 2012付属のコンパイラコンパイルされた結果は、以下のような出力を出してきた。

def constructor : 10
constructor this is 0074FBAC
x is -858993460
constructor this is 0074FBB8
x is -858993460
f.x is 20

代入にも関わらず、謎のオブジェクトが生成されテンプレートコンストラクタが呼ばれている。f.xには代入で入っていて欲しい値が正しく入っていない。
ちなみにこれは、f = funcではなくf = &funcと書くことで回避され、予想と同じ結果を出力してくれた(Clangでも同様)。これから関数(メンバ関数)を扱う際には、必ず明示的に&を付けるようにした方が安全なのかもしれない。

なお、template <class vType>とあったとして、引数を受け取り、そのvTypeをsizeof(vType)とすることで、&を付けずに代入しようとしたものをコンパイルエラーにすることが出来るので、そういう作りにして使用者にも強制するようにしている。
ちなみにVisual Studio 2012ではこのコンパイルエラーがコンストラクタの部分で働くので、最適化等で挙動が変わってしまったというより、完全にパースの時点で間違っていると思われる。

※補足としてだが、f = funcならvType = void (void)という型に推論され、f = &funcとした場合はvType = void (*)(void)と推論されているようだ。

コンパイルすら出来ないテンプレート

 VC++の倒し方知ってる?俺は知ってるよ。

template <class vType, int vType::* = nullptr> struct bar;

Visual Studio、お前はしぬ・・・!とばかりに、内部エラーが発生してはじけ飛んでくれる。これはRead Onlyのプロパティでも作ろうとした際に遭遇したコードを最小化したものである。

ちなみにこのコードはVisual Studio 2008、Visual Studio 2010、Visual Studio 2012の三種で試し、どれも同様に内部エラーが発生してコンパイルが出来ない。2013や2015はまだ試していないので、今度暇があったら・・・少なくとも2013は試しておこうと思う。

必ずメモリをリークする標準ライブラリ

 いわずもがな、Visual Studio 2012のstd::threadの事である。これは、使用してスレッドを一度でも起動すると、必ず44 Byteほどメモリをリークする。
for ( int i = 0; i < 10000; ++i ){ std::thread th( foo ); th.detach(); }
とこうしても44 Byteである。使用する回数やオブジェクトの数などは関係ないようなので、ある意味安心して使っても良いのかもしれない。良くないのかもしれない。


余談だが、Clang for Windowsを用いる時は、私はプロジェクト設定に_HAS_EXCEPTIONS=0と入れている。つまりは#define _HAS_EXCEPTIONS (0)と書いたようなものだ。これにより、未だ対応出来ていない例外をスルーしてClang for WindowsでもSTLが使えるようになる。
だが少なくともVisual Studio 2012上で、これを定義したままstd::threadを使おうとすると、__uncaught_exceptionという識別子が定義されていないとのことでコンパイルエラーが発生してしまう。せっかくなので似た名前のstd::uncaught_exceptionに置き換えるよう定義してやると、正常に(?)動いた。Clang for Windowsを用いる際には必須かもしれない。





他にもmin, max, near, farマクロ等(Visual StudioというよりはWinAPIのヘッダ)で健全なコードが汚されたり等あるが、ひとまずこの辺で終わらせておく。
早く全人類がC++11、いやC++14を当たり前のように使える世の中になりますように。

リポジトリ移行した

いい子いい子・・・djannです。


前々から持っていたリポジトリの中から、一部の環境に依存しないヘッダライブラリを切り離し、新規リポジトリへ移行させた。
移行させたのはこのブログにも書いたdepotライブラリとなる。その内容はほぼstlの一部を劣化コピーさせたようなものなので、特別有用なものではない。学習用半分、布教用半分といったところだ。


前述のようなものなので需要はないとは思うが、ひとまず自身のメモ代わりにでもこちらにURLを記述しておく。

https://bitbucket.org/djann9071/depot

特にvariantやfunction、monad辺りは最初の頃に作ったもので、templateというもの自体を手探りだった時のもので、見ていると懐かしい気分になってくる。

ラーメン屋に行った

らめぇぇぇん!djannです。


とある都内のラーメン屋にいった。有名かどうかは知らないが、そこではとんこつラーメンが売り、というかとんこつラーメンしか取り扱っていないようだ。社会人になるまで福岡で過ごしてきた私は、とんこつラーメンには一家言を持っているつもりだが、この店のラーメンはとても素晴らしかったので紹介しようと思う。


さて、券売機でチケットを買い店員に渡して少し待つとラーメンが出てきた。まずは香りを楽しもう。外に香っていたものとは違いとんこつは一切の主張を禁じられているようで、油の絡みついてくる香りが主となっている。トッピングはメンマにチャーシュー、ネギに海苔と、九州的なシンプルなものだ。

スープを一口すする。とても濃厚なスープだった。とんこつの味はほぼ感じられず、代わりに飲むと喉が痛くなっていくという、関東では稀に頻繁にたまによく遭遇する濃さを持ったスープだ。意識して飲み進めると、少しずつ頭も痛くなってきた。忙しい現代人に、病欠という休息をプレゼントしようとしてくれているのかもしれない。実に素晴らしい。

次にメンマだ。かなり太めで、1~2cmほどの太さがある直方体の形をしている。かじると中からは甘みが噴出してきた。
じっくりと味が浸透しており、スープの中に入っているのに外も中もとても冷たい事を除けば、非の打ちどころがない。この冷たさは「これが歯に沁みるようなら早く病院に行こう。」という早期発見を促す為のギミックなのだろう。

さて、ではメインの麺に行こう。福岡!と銘打っているだけあって、ストレート麺のようだ。太さは細麺にしては太く、太麺にしては細い。中麺という太さはあるのだろうか?ラーメン知識があるというわけではないので分からない。
麺を箸でひきあげ、一気にすする。元々とんこつ味がそこまで無いスープだったが、更に麺へほとんど絡まずその油分だけが麺へ染みついてくる。そのまま口の中が一気に油で一杯になる。身体中がべとべになってしまったかのような錯覚に陥ってしまった。身体の潤いが足りない人達へ配慮してのことだろう。きっと食べた後は、50代の太ったおじさんのようにモチモチとした肌になっていること間違いなしだ。

この素晴らしいラーメンの中、救いとして現れたのは海苔である。何とも言えない、何とも言いようのない、強いて言うとするならば、普通である。油臭くもなく、冷たくもない。ただしなびているだけで、とても普通の海苔だ。口に入れるとギシギシと音が鳴る。スープに染みさせても半端だとギシギシと鳴りつづける。きっと強靭な肉体に鍛え上げた海苔なのだろう。味は本当に普通だ。海苔だ。多分海苔だ。ノリは悪いが。

麺以外のメインを張る具材、チャーシューを食べてみると、舌の上でとろけた。見事に油と脂とアブラに変換された。そして口の中には、子供の頃に行った病院を思い出させる薬の香りが一杯に広がり、自分は今不健康であると少しずつ洗脳されていくようだった。そしてこちらも、メンマと同様に冷たい。スープに浮かぶ、風味とベトベト感のみでしか自己を主張出来ない油も温かくないので、もっと深くまで埋め込んで温めるべきだったのだろう。チャーシューはさすがメインを張る具材なだけあって、きっちりと他の具材等の悪い所の集大成 + αに仕上がっていた。一口食べれば頭痛がし、二口食べれば胃がもたれ、三口食べれば吐き気がする。今までにこんな食べ物は食べたことがない。素晴らしい。



ここまで書いた通り、ここのラーメンはとても素晴らしいものである。何より素晴らしいのは、来る度に「もう二度と来ない」と思っているにもかかわらず、たまに無性に「行かないと!」という気分になってしまうところだろう。
さて、最後になるが、あえてこの店の名前は出さないでおく。これを読んだ人にも、是非この素晴らしい店に出会ってしまい、店を出る時に後悔してほしいという慈愛に満ちた私の心遣いである。

Clang for Windows 3.6を入れた

徐々に進化している・・・徐々にだが・・・確実に!djannです。


過去にclang for windows 3.5を入れてみた - 並ゲームプログラマの書き捨て場
Clang for Windows 3.5のinstall.batの問題 - 並ゲームプログラマの書き捨て場でClang for Windows 3.5についての記事を書いた。見てみれば分かる通り、私は普段コンパイラはclang-cl.exeを使っている。

そして、ずいぶんと遅れたがLLVM Clangに3.6系統が登場しClang for Windowsも3.6がリリースされたので、もちろん入れてみた。


言い訳をすると仕事が忙しくて、素直に言うとものぐさな性格なので、これを書き始めたタイミングでは3.5から3.6で何が変わったかというのを私は知らない。ひとまず、単純な使用感の向上を求めてのバージョンアップだった。

さて、まずはインストールだが、こちらは前例たちと変わらない。インストーラを起動すれば旧バージョンの存在を検出、先に旧バージョンをアンインストールするかい?と聞いてくれる。もちろんYesと返答し、そのままインストーラを進めて行くだけだ。

そして3.5で問題だったinstall.batだが、中を見ると必ずループする形に変更されていた。これならば最新のVisual Studioが入っていない環境でも、ちゃんとx64向けのプロパティファイルが設置されてくれそうだ。


さて、実際にコードを書いてみた。プログラマおなじみのHello Worldである。

#include <iostream>


int main()
{
	std::cout << "Hello, Clang for Windows 3.6!!" << std::endl;
	
	std::cin.get();
}

今回は、無駄にVisual Studioに入っていない機能を使ったり等はしなかった。ちゃんと違うコンパイラが動くというのは3.5の時に確認済みだ。いやいっそ3.4の時に確認済みだ。


が、どうやら3.5の時と同様にtry catch throwでエラーが出てしまうらしい。内容もこれまた同様に、例外はまだコンパイル出来ないとのこと。
詳しく見ることが出来ていないので、もしかしたら3.5が使用されていますよ☆ということかもしれないが、ひとまずそんなところだ。3.5と同様に#define _HAS_EXCEPTIONS (0)を定義しておくことで、標準ライブラリを使用することが出来る。



うむ、このままでは何が変わったのかが全く分からない。表面的な部分しか舐めていないからだ。
この記事一旦下書きにしていたのだが、せっかくだから追加を書きながら、変更点を見てみることにした。自分に関わりそうなWindows Supportの部分だけではあるが。
参照元はこちら

・沢山のバグ修正が行われた
・x86x64環境でVisual C++を用いたセルフホストが可能になった?例外を除くMicrosoft C++ ABIに対応した。
・ATLやWRLヘッダを使えるようにVisual C++に合わせたハックを追加。
・Visual C++の__superキーワードを解釈できるように追加。
・Visual C++等での__vectorcall呼び出し規約が追加された。これはVisual Studio 2015のSTLで使われている。
・COFFファイルへデバグ情報を入れる為の基本サポートが行われる。
・筆者は英語が読めない。

つまりは、例外はいまだ使えない。今まで出来なかったブレークポイント*1とステップ実行が出来る・・・のか?これを書いている現在は試せる状況ではないので、後で各種実際にどういう挙動かを試してみたいと思う。もしかしたらブレークポイントはおけないかもしれない。いや置けない気しかしない。

試した場合は、以下に追記を書く予定だ。土曜日か日曜日、下手すれば更に先になってしまうだろうが。
※以下の追記にブレークポイントのテストを行った記録等は一切ない。別の部分の読み間違いから勘違いし続けている完全に無意味な文章なので注意。なおブレークポイントの情報は注記を行った。

追記その1

ATLやWRLの使用が可能なようにハック・・・辺りが簡素過ぎたので、明確にするためVisual Studioでしか通らないテンプレート周りのコードを試した*2。が、なんとClang for Windows 3.5でも以下のコードは通ってしまうようだ。警告付きだが(なお、テスト環境はVisual Studio 2010 Pro + Clang for Windows 3.5である)

template <class vType>
void print(){
	vType::type val = 0;
}

なお、Visual Studio 2010では一切の警告無しに通る。
他、インナーテンプレートクラスのクラススコープ内の特殊化等も、同様にVisual Studio 2010では一切の警告無く、Clang for Windows 3.5では警告を出しつつビルドが通った。どうやら結構な部分は、既に「VC++の独自拡張、汚い構文だ」と認識しつつコンパイル出来るようだ。過去のリリースノートの読破と、Visual Studioの独自構文への造詣を持つ必要があるようだ。

追記その2

commonly known template pattern (not to be confused with C++ templates). The template pattern is often implemented by having an abstract base interface class that all the subtype classes inherit from.
という文面を見つけた。テンプレート引数そのままではなく、基底クラスで実装されたサブタイプを派生クラスで使用できるということなのか?とすると、以下のような感じか?

template <class T>
struct base {
	using type = T;
};
template <class T>
struct derived : public base<T> {
	type val;	// ここが少なくともMSVCの拡張.
};

一応、ちゃんと以下のように警告が出てくれた。

warning : use of identifier 'type' found via unqualified lookup into dependent bases of class templates is a Microsoft extension [-Wmicrosoft]
          type val;

果たしてこれが3.6で追加されたものなのか、明日試してみなければならないだろう。これも3.5で実装済みであれば、また有用そうな情報を探すか、または英語をかっちりと学ぶ必要がある。

追記その3

追記その2で書いたことだが、3.5でも同様の結果になった。ではこれならばどうだ?と、3.5で通らずにVisual Studio 2010で通る以下のコードを書いてみた。

struct foo {
	typedef float type;
};
template <class vType>
struct base : public foo {
};
template <class vType>
struct derived : public sub<vType> {
	type val;
};

一段階経由することで、3.5で通らない形になり、それでもVisual Studi 2010では通る形だ。all the subtype classes inherit fromとはそれを指しているのではないか!と期待したのだが、どうやら3.6でも同様にビルドが通らない・・・。


ここでふと思った。原文に書いてあるknown template patternの部分だが、別段イタリックでもなんでもなく、いたって平凡なフォントである。英語圏では、何らかの用語などはイタリックにする等、見た目でそれが用語だと分かるようにする文化があると聞いた事がある。
つまり「known template pattern」という一定のパターンがあるわけではなく、あくまでただの説明として(この辺の良く知られてる、テンプレートに対するMSVC特有の名前検索パターンを取り入れたぜ。のような意味で)書かれていただけなのではないだろうか。それはいくら調べてもほとんど情報が出てこないわけだ。

一部の単語を見て早とちりした結果、この追記群は全く無意味な文章(私の無知さを辱めるという使い道はあるが)となってしまった。今後このような事がないようにする戒めとして、この記事はこのまま残しておくことにし、以降追記等は行わずに放置しよう。

*1:ブレークポイントは、今までもエディットコンティニュを考慮しないデバグ情報を埋め込むよう指定していれば置くことが出来、ステップ実行も可能だった。出来ないのは変数の内容を見る等である。なお、これは3.6でも同様なようだ。

*2:参照元の原文は「Added more MSVC compatibility hacks, such as allowing more lookup into dependent bases of class templates when there is a known template pattern. As a result, applications using Active Template Library (ATL) or Windows Runtime Library (WRL) headers should compile correctly.」である

そういえばVisual Studio 2013 Community入れた

異文化?コミュニ・・・ってもうやったか。djannです。

結構間が空いたが、Visual Studio 2013 Communityをインストールした。前回とは打って変わって、特に何の問題も無くインストールが終わってしまったので、これ以上書くことはないのだが。
一つ問題があるとすれば、確かWindows Phoneのemulatorのユーザだったか。それが現在のユーザで正しく作成されなかったというエラー(警告?)が出た。まあそれだけである。

ちなみに、前回(unique_ptrでrange-based-for - 並ゲームプログラマの書き捨て場)の記事のコードはこれで書いた。わしの勝ちのようですね。


うむむ、やはりはてな記法とやらは慣れない・・・というか自由な文字にリンクを付ける方法が分からない・・・。ググりまくるしかないか。

無意味な記事_ただのテスト

空が・・・青いなぁ・・・。djannです。

テストをしてみた

なにやらはてな記法とやらがあるらしいので、せっかくだから試してみることにした。ただそれだけの記事である。
目的は主にソースコードの表示等々である。と早速気付いたのが、HTMLが書けないっぽいということだ。これは残念だ。

見出しっていいな

どうやらアスタリスクを付けるだけで、簡単に見出しが作成できるようだ。といってもCSSが適当なおかげで、見栄えは他のはてなブログのようにはなっていないだろうが・・・。

ソースコードのテスト

スーパーpreというものがあるらしい。>||と<||で囲うことで、その間がソースコードになる。さらに最初の>||の2本のパイプ中に言語を入れることで、ハイライトまで行ってくれるという、大変便利そうなものだ。試してみよう。

#include <iostream>


int main()
{
	std::cout << "Hello, Super pre syntax!" << std::endl;
}

ほう、プレビューで見る限り、確かにハイライトまでやってくれているようだ。問題は、個人的には若干行間が空き過ぎているように感じることだ。これはどのように指定すれば調整できるのだろうか?CSSはてな記法か、はたまたいっそHTMLにすべきか。
ただまあ、特別な機能を用いなくとも、見たまま記法よりは記述しやすいということは確かだ。HTMLが記述出来ないのは難点だが・・・。