Entries

スポンサーサイト

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

parse_config_file

タグ: C++ Boost

コマンドライン引数解析ライブラリ Boost.Program options には、コマンドライン引数の他に、 config file を解析するパーサが付いている。
しかしこの config file 、文中に何度か出てくる割に、書式の説明がない。
説明がないということは、もしかしたらこれはとんでもなく常識的なこと(説明するまでもなく一意に定まること)なのかもしれないのだが、どうも「これに相違ない」というものを発見できなかったので、テストコードを参考に書式を推測してみることにした。

参考にするのは Boost 1.34.1 の parsers_test.cpp の test_config_file() 。
見易くするため、 config file の中身に相当するリテラルを分けて記述する。

まずは config file 。

 gv1 = 0#asd
plug3 = 7
b = true
[m1]
v1 = 1

v2 = 2

そして test_config_file() 。

options_description desc;
desc.add_options()
    ("gv1", new untyped_value)
    ("gv2", new untyped_value)
    ("plug*", new untyped_value)
    ("m1.v1", new untyped_value)
    ("m1.v2", new untyped_value)
    ("b", bool_switch())
;

const char content1[] = "config file リテラル"

stringstream ss(content1);
vector<option> a1 = parse_config_file(ss, desc).options;
BOOST_REQUIRE(a1.size() == 5);
check_value(a1[0], "gv1", "0");
check_value(a1[1], "plug3", "7");
check_value(a1[2], "b", "true");
check_value(a1[3], "m1.v1", "1");
check_value(a1[4], "m1.v2", "2");

このテスト内容から推測できるのは、大体こんなところか。

  • 改行区切りである
  • name 前後、 value 前のスペースは無視される(それ以外のスペースやタブについては不明)
  • "#" 以降の文字は無視される
  • 空行は無視される
  • "[section name]" はセクション(Windowsの初期化ファイルのあれ)の開始を示す
  • セクション内の name は "section name.key name" という形になる

当然ながら、これはあくまでも「現版のテスト内容から推測したもの」であって、正式な仕様であることを保証するものではない。

それにしても

("plug*", new untyped_value)

オプション名定義でワイルドカードを使えるとは、知らなかった。
これもドキュメントにはないようだけど、使っていいのかな。

ATH-ANC3 購入

タグ: ATH-ANC3

今まではずっとiPod touchに付属してきたイヤホンを使っていたのだが、こいつは「音漏れさせずに十分な音量を得ること」が非常に難しい。
それでも何とかはめ方でカバーできないかとぐりぐり試行錯誤していたら、ある日イヤホンに血が付いていることに気付いた。
いやあ、なんか合わないな、痛いなとは思っていたんだけど……

そんなわけで、私では付属のイヤホンを使いこなすことは無理ということに思い至り、やむなく新しいのを買うことに。

とりあえず「音漏れしなくて」「新しくて」「面白そうなの」が欲しかったので、最近発売されたこれを購入。
私にとって初のカナル型、初のノイズキャンセラーである。

2日ほど使ってみた感じ、音質については特に問題ない。
まあ、そもそもiPod touch付属のイヤホンで聞いていて聞こえていない音に気付いても「まあいいや」とスルーする程度の感性なので、あまり当てにはならないが。
でも付属イヤホンよりは遥かに良い。これは間違いない。
ただ、無音状態でもサーというノイズを拾ってくるのが少し気になるかな。

意外だったのは、ノイズキャンセラーの効果が思いのほか高いこと。
てっきり「気持ち外の音が小さくなる程度」のものだと思っていたのだが、想像以上に静まり返る。
エアコンの動作音、PCのファンの音、電車や自動車の走行音などは、それと気付かないほど。
ただ、効果の強い音と弱い音はあるようで、電車の車内アナウンスなどは割と抜けてくる。
打鍵音などは面白く、普段は「スコスコ」なのが「カチャカチャ」になったりする。

なお、キャンセラーを入れると、サーというノイズは若干大きくなる。
iPod touchの場合はそれでも許容範囲なのだが、MacBook Proに繋いだ場合はそれに謎の重低音が加わって、かなり気持ちの悪いことになる。
接続する機器によっては使い物にならないかも知れない。

キャンセラーのON/OFFはコードの途中に付いているコントロールボックスで操作するの。
これの位置が微妙に悪い。
接続する機器から20cmのところにあるため、クリップを胸ポケットに留めてしまうと、iPod touchの操作が窮屈になる。
かといって、留めないなら留めないで邪魔。
延長ケーブルもあるが、しかし総延長は十分足りているわけで、うーむ。

とまあ、こんな感じで性能に関しては概ね満足。
密閉型なので外音を取り込む(音楽を外音に対するBGMにする)ことができないのが残念だが、これに関してはイヤホンをしっかりはめ込まず、引っかける程度にすればよいことに気付いたので問題なくなった。
そんな使い方でも、なおもって付属のイヤホンより良く聞こえるのが何とも。

02月24日のココロ日記(BlogPet)

今度いいカレーをつくります!ぜったいつくります!

*このエントリは、ブログペットのココロが書いてます♪

苦労人KAITO

クリプトン・フューチャー・メディアに聞く(2):「初音ミク」ができるまで - ITmedia News

その8カ月後に出した日本初のボーカロイド「MEIKO」(女声)は大ヒットした。開発したのはクリプトン・フューチャー・メディア(札幌市)。1000本売れたらヒットと言われるバーチャルインストゥルメント市場で約3000本(当時)売り上げ、新記録を打ち立てた。

実はMEIKOって売れっ子だったのね。

だが次の「KAITO」(男声)はまるでダメ。06年2月に発売し、500本(当時)しか売れなかった。

KAITO…… ・゚・(つД`)・゚・

しかしそんな不遇な時代を過ごした彼も、ミクの登場によって「お兄ちゃん」になり、アイスの王子になり、卑怯になり、調整の難しさから聴衆を度々ずっこけさせ、しかし時に素晴らしい歌声を披露し、ついにはニコニコ市場で360本を売り上げるほどの人気を獲得するに至る。

私自身、ニコニコ動画でミクが流行るまでVOCALOIDの存在なんて知らなかったが、今となってはすっかりKAITOのファンだ。

MEIKOと同様のコンセプトで送り出した男声ボーカロイド「KAITO」はしかし、さっぱり売れなかった。DTM市場は男性が8割。「男じゃダメなんだと思った」と、2人は苦笑する。

男声だから売れなかったというのは確かにあるかもしれない。
しかしそれもマーケティング次第。
MEIKOの売り方がKAITOには適応しなかっただけで、KAITOにはKAITOなりの売り方があった。
そういうことなのだろう。

本日見かけた酷いコード8

タグ: C++ 酷いコード
// 構造体 ○○byte
struct StaticBuffer
{
	DWORD foo[sizeof(Foo) * FOO_ARRAY_MAX / 4];
	DWORD bar[sizeof(Bar) * BAR_ARRAY_MAX / 4];
	DWORD baz[sizeof(Baz) * BAZ_ARRAY_MAX / 4];
	DWORD hoge[HOGE_BUFFER_SIZE / 4];
	DWORD fuga[FUGA_BUFFER_SIZE / 4];
	// …… 以下、同じようなコードが続く ……
};

酷いコード1の亜種。
原種同様、各メンバは reinterpret_cast で型変換して使用する。
書き方がアクロバティックなだけで動作に支障のない原種とは異なり、こちらは構造体のサイズや *_BUFFFER_SIZE が4の倍数になっていない場合、十分なサイズのメモリ領域を確保できない可能性がある。

元のコードでは、各構造体は4の倍数バイトになるようパディングが入れられていて、その上構造体アライメントが8なので、まず問題にはならない。
念のため、構造体サイズや *_BUFFER_SIZE の値が4の倍数であることを確認する静的表明を入れてみたが、ちゃんとコンパイルできた。
しかし保守性は低い(コード中には4の倍数バイトにすること等の注意書きはない)し、何よりこの構造体や Foo 、 Bar 等のコメントに記されている「○○byte」の値がことごとく間違っているのが、実は一番「酷い」点だったりする。

ニコニコRPGのバーサーカーソウル

タグ: C++

この作品のバーサーカーソウルは、「発動条件:MP80以上」「発動コスト:MP全て」という設定や、発動時の仰々しい演出から考えるに、遊戯の切り札として設計されているように思われる。
しかし実際に使っているところをみると、300程度のダメージを与えるだけでターンエンドすることが多く、燃費の悪い魅せ技という印象が強い。

そもそもこのカードのダメージ計算式はどうなっているのか。
作者のマイリストにはこう書いてある。

バーサーカーソウルの効果は30/40の確率で150ダメージの攻撃。その後成功確率を1/40ずつ減らしながら連続攻撃。

ではこの式をもとに、バーサーカーソウルで与えられるダメージの期待値を計算してみよう。

#include <iostream>
#include <boost/format.hpp>

void play_berserker_soul(int deck_cards, int monster_cards)
{
	int damage = 0; // 累計ダメージ
	double my_turn = 1.0; // ターン到達率
	double expect = 0.0; // 期待値

	boost::format form("%2d %4d %#12g (%f)");

	while(monster_cards > 0)
	{
		// モンスターカードを引く確率
		const double draw_monster_card =
			static_cast<double>(monster_cards--) /
			deck_cards;

		damage += 150;
		my_turn *= draw_monster_card;

		expect +=
			damage *
			my_turn *
			(deck_cards - monster_cards) / deck_cards;

		std::cout
			<< form % monster_cards % damage % my_turn % expect
			<< std::endl;
	}

	std::cout << "期待値: " << expect << std::endl;
}

int main(int argc, char* argv[])
{
	play_berserker_soul(40, 30);
	return 0;
}

以下はこの実行結果。
左から「モンスターカード残数」「累計ダメージ」「ターン到達率」「計算途中の期待値(確認用)」。

29  150     0.750000 (30.9375)
28  300     0.543750 (79.875)
27  450     0.380625 (135.541)
26  600     0.256922 (189.495)
25  750     0.166999 (236.464)
24  900     0.104375 (274.038)
23 1050    0.0626247 (301.985)
22 1200    0.0360092 (321.43)
21 1350    0.0198051 (334.13)
20 1500    0.0103977 (341.928)
19 1650   0.00519883 (346.431)
18 1800   0.00246944 (348.876)
17 1950   0.00111125 (350.122)
16 2100  0.000472281 (350.717)
15 2250  0.000188912 (350.983)
14 2400  7.08422e-05 (351.093)
13 2550  2.47948e-05 (351.136)
12 2700  8.05830e-06 (351.151)
11 2850  2.41749e-06 (351.156)
10 3000  6.64809e-07 (351.158)
 9 3150  1.66202e-07 (351.158)
 8 3300  3.73955e-08 (351.158)
 7 3450  7.47911e-09 (351.158)
 6 3600  1.30884e-09 (351.158)
 5 3750  1.96327e-10 (351.158)
 4 3900  2.45408e-11 (351.158)
 3 4050  2.45408e-12 (351.158)
 2 4200  1.84056e-13 (351.158)
 1 4350  9.20281e-15 (351.158)
 0 4500  2.30070e-16 (351.158)
期待値: 351.158

極端に弱いわけではないが……MP全消費というリスクや演出の長さを考えると、やはり魅せ技と捉えざるをえない。

なお、今回の計算は作者のコメント通り「デッキのカード総数は常に40枚でモンスターカードの数だけが減っていく」という条件で行っているが、もしこれを「カードを引く度にデッキのカード総数も減る」ことにした場合、ダメージの期待値は409.091となり、最高ダメージを拝める確率も0.0000001%まで上昇する。
これなら実用性も……あるか?

Xpressive と Spirit の実行速度

タグ: C++ Boost

Boost.XpressiveBoost.Spirit
似た文法を持つこの2つ、どちらを使うべきかよく迷うので、一つの判断基準として実行速度を比べてみることにした。

使用する Boost は trunk のリビジョン43351。
処理の内容は「ドット区切りのDMS文字列を実数値にする」というもので、ついでに「0?360°のみ」「分の値は0?59」「秒は整数部を0?59で表記し、必要が有れば小数点以下を10進法で記しても良い」などの条件を付ける。
ソースとなるDMS文字列は「0?360°」「360°」「360°?」から1つずつ選択。
その文字列1つにつき

  • Xpressive ( regex 使い捨て)
  • Xpressive ( regex 使い回し)
  • Spirit ( grammar 使い捨て)
  • Spirit ( grammar 使い回し)

の4パターンの処理に掛かる時間を計測する。

#include <boost/xpressive/xpressive_static.hpp>
#include <boost/xpressive/regex_actions.hpp>
#include <boost/spirit.hpp>
#include <boost/spirit/dynamic/switch.hpp>
#include <boost/timer.hpp>

template <typename Iterator>
inline boost::xpressive::basic_regex<Iterator>
make_xpressive_parser(double& result)
{
	using namespace boost::xpressive;

	return
		(
			"360." >>
			repeat<1, 2>('0') >> '.' >>
			repeat<1, 2>('0') >> !('.' >> +as_xpr('0'))
		)[ref(result) = 360.0] |
		(
			repeat<1, 3>(_d)[check((ref(result) = as<int>(_)) < 360)] >> '.' >>
			(! range('0', '5') >> _d)[ref(result) += as<int>(_) / 60.0] >> '.' >>
			(! range('0', '5') >> _d >> !('.' >> +_d))[ref(result) += as<double>(_) / 3600.0]
		);
}

struct dms_grammar : public boost::spirit::grammar<dms_grammar>
{
	dms_grammar(double& result) :
	m_result(result)
	{
	}

	double& m_result;

	template <typename Scannar>
	struct definition
	{
		boost::spirit::rule<Scannar> expr;

		definition(const dms_grammar& self)
		{
			using namespace boost::spirit;
			using phoenix::arg1;
			using phoenix::var;
			using phoenix::val;
			using phoenix::static_cast_;

			expr =
				(
					"360." >>
					repeat_p(1, 2)[ch_p('0')] >> '.' >>
					repeat_p(1, 2)[ch_p('0')] >> ! ('.' >> +ch_p('0'))
				)[var(self.m_result) = 360.0] |
				(
					(uint_parser<unsigned int, 10, 1, 3>())[var(self.m_result) = arg1] >>
					switch_p(val(self.m_result) < 360)
					[
						case_p<true>(ch_p('.')),
						case_p<false>(nothing_p)
					] >>
					eps_p
					(
						((range_p('0', '5') >> digit_p) | digit_p) >> '.'
					) >> uint_p[var(self.m_result) += static_cast_<double>(arg1) / 60.0] >> '.' >>
					eps_p
					(
						((range_p('0', '5') >> digit_p) | digit_p) >> ! ('.' >> +digit_p)
					) >> ureal_p[var(self.m_result) += arg1 / 3600.0]
				);
		}

		const boost::spirit::rule<Scannar>& start() const
		{
			return expr;
		}	
	};
};

void test(const char* str)
{
	const int roop = 100000;
	double degree;

	std::cout << "[" << str << "]" << std::endl;

	{
		const boost::timer t;
		for(int i = 0; i < roop; i++)
		{
			regex_match(str, make_xpressive_parser<const char*>(degree));
		}
		std::cout << "xpressive 1: " << t.elapsed() << " s" << std::endl;
	}

	{
		const boost::xpressive::basic_regex<const char*>
			regex(make_xpressive_parser<const char*>(degree));

		const boost::timer t;
		for(int i = 0; i < roop; i++)
		{
			regex_match(str, regex);
		}
		std::cout << "xpressive 2: " << t.elapsed() << " s" << std::endl;
	}

	{
		const boost::timer t;
		for(int i = 0; i < roop; i++)
		{
			parse(str, dms_grammar(degree));
		}
		std::cout << "spirit 1: " << t.elapsed() << " s" << std::endl;
	}


	{
		const dms_grammar grammar(degree);

		const boost::timer t;
		for(int i = 0; i < roop; i++)
		{
			parse(str, grammar);
		}
		std::cout << "spirit 2: " << t.elapsed() << " s" << std::endl;
	}
}

int main(int argc, char* argv[])
{
	test("123.45.6.7");
	test("360.0.0.0");
	test("361.0.1.2");
	return 0;
}

厳密にテストしたわけではないので、期待通りの実装になっているか分からないが、とりあえず気にしない。

これを Windows XP + Pentium4 3.6GHz + VS2005 でリリースビルドした結果がこれ。

[123.45.6.7]
xpressive 1: 4.203 s
xpressive 2: 2.421 s
spirit 1: 0.344 s
spirit 2: 0.094 s
[360.0.0.0]
xpressive 1: 2.125 s
xpressive 2: 0.328 s
spirit 1: 0.25 s
spirit 2: 0.016 s
[361.0.1.2]
xpressive 1: 3.844 s
xpressive 2: 1.891 s
spirit 1: 0.281 s
spirit 2: 0.031 s

Mac OS X 10.5.2 + Core Duo 2.0GHz + gcc4.0.1 で -O3 ビルドした結果はこう。

[123.45.6.7]
xpressive 1: 3.80625 s
xpressive 2: 1.30441 s
spirit 1: 0.29001 s
spirit 2: 0.06282 s
[360.0.0.0]
xpressive 1: 2.55803 s
xpressive 2: 0.189298 s
spirit 1: 0.246766 s
spirit 2: 0.019943 s
[361.0.1.2]
xpressive 1: 3.25801 s
xpressive 2: 0.742447 s
spirit 1: 0.24665 s
spirit 2: 0.020515 s

見ての通り、速度的には Spirit の方が速い。
しかし書きやすさという点では Xpressive の方が上。
その辺は後発で、しかもちゃんとした正規表現なだけはある。

デバッグ版では再現しません

カップ式の自動販売機でコーヒーを買った。

カップが出なかった。

故障だろうかと、水(無料)のボタン押してみた。
カップが2個重なって落ちてきた。

どうやらつっかえていただけのようだ
私は再びお金を入れ、コーヒーのボタンを押した。

カップは出なかった。

( ゚Д゚) オノレ……

二次属性の継承

陵桜学園 桜藤祭で「ギルガメッシュ」に扮するみさおを見て思ったこと。

「ドル……アーガ?」

Fate未見の私が「金色の鎧を着たギルガメッシュ」というシンボルを見て真っ先に思い浮かぶのは、『ドルアーガの塔』のギル。
なので一瞬「もしやここだけ意表を突いて別ゲームの格好を?」などと考えたが、もちろんそんなことはなく。
Fateでも、彼はちゃんと金ぴか鎧に身を包んでいる。

しかしなぜこの格好なのだろう。
原典でも同じような格好をしているのだろうか。
シュメールってそういう英雄を創るところだっけ……

疑問に思い調べてみると、どうやらFateのギルガメッシュの鎧は、まさにその『ドルアーガの塔』のギルのイメージで描かれたものらしい。
なるほど、そりゃあ似ていると思うわけだ。

んー、でもまあこっちのギルは、イシターのギルのようにマスターの尻に敷かれているようではないかなー?

02月17日のココロ日記(BlogPet)

今度、ブログ妖精の世界にむいさんを連れていってあげますね!

*このエントリは、ブログペットのココロが書いてます♪

あっちを記事にしたついでに

以前記事にした『こなたとかがみのファイナルファンタジー?』のパクリ元動画の最新版。
パクリと言っても、この動画が「らき☆すたの登場人物たちがドラクエをプレイする」というコンセプトのものであるのに対し、FFの方は言ってみれば「作者がFFのキャラ名を変えてプレイしながら妄想した」ようなもの。
パクっているのは名前だけで、動画のコンセプトは全く異なる。

でまあこのシリーズは、ネタの上手さもさることながら、何よりキャラの動かし方がとても「らしい」。
今作で言えば、いつもは見ているだけであまり自分では操作しないゲームを、ドキドキしながらしかし楽しそうにプレイする(という設定の)つかさの描写は、背景の曲も相まって、実に秀逸。

そして今回、特に感銘を受けたセリフはこれ。

お、カニが増えたぞ
おもしれーな

別にカニが増えても面白くはない。
面白くないのだが、みさおが言うと、何故だかこれがとても楽しいことのように思えてくる。
ほんの一言ではあるが、キャラを捉えた素敵なセリフであるといえよう。

犯人はやはりお前……か?

タグ: Mac Leopard

久しぶりにMacがシステム終了しない状況に陥る。
うざったいことだが、前回推測したとおり、iDiskをアンマウントできないことが原因であるかを調べる絶好のチャンスでもある。

というわけで、iDiskを強制アンマウントするコマンドを打つためDockのTerminalをクリック。

……起動しない (;´Д`)

うう、Terminalは常に起動させておくべきだったか。
しょうがないので、LANケーブルをぶちっと抜く。
すると、しばらくしてiDiskとNASへの接続が切断されたことが通知され、同時にTerminalが起動。
何か色々と詰まっていたものが処理され、見事システムを終了させることができた。

以上のことより、私を悩ませていた「システム終了しない病」は、iDisk(あるいはNAS)との接続に問題がありそうだということが判明した。
NASか……そういえばこれもLeopardとほぼ同時期に導入したんだよなぁ。
iDiskの方がずっと怪しい(実際、アンマウントできないことあるし)が、NASの線も捨てきれないか。

動画を見て、省みる

FF4の導入部を上手くいじり、流れはほとんど変えず、しかし原作を越えた盛り上がりを見せてくれる。
「希望は何も見えないけれど、それでも今は、信頼できる仲間と前に進んでみよう」
という、物悲しいながらも力強さを感じさせる展開を、実に上手く描けている。
今回は導入部だけだが、このまま終わっても全然問題ない。
というより、むしろ終わった方がいいのかもしれない。

正直、勿体ないと思う。
外見はFF4にらき☆すたのキャラを被せたものだけれど、このキャラ設定でらき☆すたを使う必然性は薄い。
ならばもう一歩踏み込んで、「パクリである」などという逃げ口上付きの作品などにせず、オリジナルと主張できる域まで昇華させてみてほしかった。

……もっとも、オリジナルとして世に出た場合、私が見たかというと、恐らく見なかっただろう。
普段オリジナル作品を望んでいる割に、買っているのはシリーズ物ばかりという矛盾。
いかんなぁ、口ばっかりで行動は守りに入ってるなぁ。

本日見かけた酷いコード7

タグ: C++ 酷いコード
class ImplBase
{
public:
	virtual ~ImplBase();
	
	virtual void func1() = 0;
	virtual void func2() = 0;
};
class ImplBase;

class InterfaceBase
{
public:
	virtual ~InterfaceBase();

	virtual void func1();
	virtual void func2();
	
protected:
	virtual ImplBase* GetImplBase() = 0;	
};
void InterfaceBase::func1()
{
	GetImplBase()->func1();
}

void InterfaceBase::func2()
{
	GetImplBase()->func2();
}

pimplのようなもの……かな。
InterfaceBase に関してはもっと良い設計がありそうなものだが、ここでは不問とする。

class Impl; // ImplBase を実装したクラス

class Interface
{
public:
	Interface();

	virtual void func1();
	virtual void func2();

protected:	
	virtual ImplBase* GetImplBase();
	virtual Impl* GetImpl();
	
private:
	Impl* m_impl;
};
Interface::Interface()
{
	m_impl = new Impl;
}

ImplBase* Interface::GetImplBase()
{
	return m_impl;
}

Impl* Interface::GetImpl()
{
	return m_impl;
}

void Interface::func1()
{
	GetImpl()->func1();
}

void Interface::func2()
{
	GetImpl()->func2();
}

Interface で func1() と func2() がオーバーライドされている。
だがこのコード、やっていることはオーバーライド元と同じでは?
まさか GetImplBase() と GetImpl() で返す値を変えるとか、そんな禍々しいことをするわけでもあるまいし。
どうして同じことを2回書くかな?2回書くかな?

この例ではメソッドを2つしか書いていないが、実際にはこのクラスには50以上のメソッドがあり、それらの多くがこの例同様無駄にオーバーライドされている(全てではない。違う挙動にオーバーライドされているものもある)。
そしてさらに、同じような設計のクラスはこれ以外にも何十セットと存在している。

まあパターンだから、確認自体は慣れればそれなりに手早く行えるようにはなる。
しかしこれを修正するとなるとかなり面倒で、インターフェースから修正する必要がある場合は4クラス全てに手を加えなければならない。

……むー、なんでこんな面倒なことになっているのだ?

たまにはココロさんが持ってきたニュースを読む

早大名誉教授の大槻義彦さんに聞く スピリチュアル番組問題(上)

また、オーラの色が見えるといい、「あなたには、情熱的な赤と知性的な青が同時に見える」とおっしゃいます。しかし、これは物理学の3原色の理論を無視しています。赤と青が交じった光を同時に見ると別の色に見えるんです。もし、分離した色が見えるのなら、江原さんにはカラーテレビは見えないはずです。だから、3原色のオーラ占いはデタラメなんですよ。

「人に『見える』のは光学情報のみである」という前提に立ったお話。
視覚以外の感覚情報(聴覚や嗅覚等)を光学情報の様に認識する「共感覚」には触れていないが、これに関しては「共感覚も3原色の理論に則る」か、「共感覚など科学的ではない」といったところか。

うーん、しかし共感覚はプラズマ以上に超常現象に対して便利な概念だと思うんだけど、わざわざ自分から捨て去るとは。
やはりこの教授はあれか、プラズマフェチなのか。

機械に心を読まれた日

この記事どこぞのマスコットみたいに、他キャラと連動して漫才でもしてくれたらと書いたところ、Goolge AdSenseが『まゆらまにあくす』を選んできた。

……どんだけピンポイントな選択だよ!

本日見かけた酷いコード6

タグ: C++ 酷いコード Doxygen
class Base
{
public:
	static const int id1;
	static const int id2;
	static const int id3;
	
	/**
	 * @param id [IN]
	 */
	virtual void operation(int& id);
};
/**
 * @param id [OUT]
 */
void Base::operation(int& id)
{
	/* ... */
}
class Derived : public Base
{
public:
	/**
	 * @param id [IN]
	 */
	virtual void operation(int& id);
};
void foo(Base* base)
{
	base->operation(static_cast<int>(Base::id1));

重要な点以外のコードを省略&改変しているため、問題点が分かり辛くなっている感があるが……

まずこのコードは、関数 foo() に於いて Base::operation() の非const参照引数に一時変数を渡しているため、今時のコンパイラでは大抵コンパイルエラーとなる。
実際、非const参照仮引数の実引数として一時変数を渡されても仕方がなく、このコードでも引数が参照である必要はない。
それはコメントに [IN](普通に考えれば入力引数を意味する)と書かれていることからも分かる。
だから、単に参照をはずしてしまえば良い、そう思って関数定義側を見てみると、なんとしたことか、こちら側では [OUT](常識的に考えると出力引数)ということになっている。
これは一体どういうことだろう。

結論から言えば、 [OUT] は間違いで [IN] が正しい。
修正ミス(元は出力変数だったのを入力変数にした、とか)か加筆ミス(非const参照は出力用だろうと常識的に考えてコメントを追加した)かは分からないが、なんにしてもこれは「コメント過多」が引き起こす弊害の最たる例と言えよう。

そもそもDoxygen用のコメントは「コード仕様をコードと別に用意して二重保守」という面倒な状態を回避するためにあるのに、「宣言部と定義部で同じコメントを付けて二重保守」とか、なにゆえそんな無駄なことをしたがるか。
Base::operation() のコメントは宣言か定義のどちらか一方にだけあれば良い。
Derived::operation() のコメントも、 Base のものから特に追記することがなければ不要。
何もコメントしなければ、オーバーライド元のコメントが勝手にくっついてくる。
もし何か追記したいことがあるのであれば

/**
 * @copydoc Base::operation()
 * 追記?
 */

とでも書けば良い。

ついでに言えば、引数の入出力属性はDoxygenに専用の記法が用意されているのだから、元のコメントも

/**
 * @param id [IN] 引数説明
 */

とか止めて

/**
 * @param[in] id 引数説明
 */

とするべき。

なんというか……もうちょっと「後で楽になること」を追求してほしいと思う。

02月10日のココロ日記(BlogPet)

今日は何書こうかな????(……1時間後)はぅぅ!いつの間にか眠ってました。いいです、明日書きます。

*このエントリは、ブログペットのココロが書いてます♪

陵桜学園 桜藤祭 デスクトップアクセサリー

ParallelsのCoherenceモードは、この手のものためにあると言っても過言ではない。

デスクトップアクセサリ on Parallels

Coherenceモードでは、最前列確保!(top most)設定にした窓は全ての操作スペースに登場する。
こういったアクセサリ系は常に引っ付いてきて欲しいものだから、これはなかなか都合が良い。
そしてWindows窓は、例えWindows側でtop mostであってもMac上では最上位のZ軸を与えられないため、常に最前面に表示されるということにはならない(普通にMac窓の裏側に回る)。
これは良くもあり悪くもあり。
私としては、半透明とはいえこんなでかいのが被さってくるのは邪魔だから、「全ての操作スペースに登場するけれどMac窓には隠れてくれてくれる」のは嬉しいのだが。

それにしても……
Windows窓の間にMac窓を挟んでもちゃんとウィンドウの透過処理を行ってくれるとか、Coherenceモードが登場した時はここまでやってくれるとは思わなかったなぁ。

でも、ぶっちゃけ、デスクトップアクセサリとか使わないよね。
一度こなたの時報聞いたらあとはいいかなー……と思ったら、これ時間ごとにセリフ変わるのね。
しかも放っておくとなんか勝手に喋って、喋ったセリフが随時ボイスコレクションに追加されていく。
ということはもしかして、これが一定数溜まると謎の設定項目が解放されるのか?

(=ω=.)こっち見んな

むぅ、そうこられてはしばらく置かざるをえまい。
複数起動していると時報がやかましいので、とりあえずこなただけ。
どこぞのマスコットみたいに、他キャラと連動して漫才でもしてくれたら良いのだが。

02月03日のココロ日記(BlogPet)

南の島で削除と一緒に泳いだら楽しそうですよね。むいさんも一緒に来てくれるかな……

*このエントリは、ブログペットのココロが書いてます♪

らき☆すた ?陵桜学園 桜藤祭?

とりあえず一周クリア。
思っていたよりずっと楽しめた。

続きを読む

Appendix

タグ

Blog内検索

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