『地球ドラマチック』(NHK) 「"永遠の命"は実現できるか!?」
人間の耳の形に細胞を増殖させてねずみの背中に移植する実験. 普通にちょこまか動いてるだけに, 見た目がかなりグロテスク. 全然関係ないけどたまたまちょっと前に読んだ『Re-born はじまりの』収録の「コワリョーフの鼻」(中島京子). 『鼻』(ゴーゴリ)のように"鼻"がそのへんを歩いてるという荒唐無稽な話が, 現実味があると思っただけでかなりシュール.
他人の臓器から細胞だけを取り去った残りの骨組み(みたいなもの?)に自分の細胞を培養して, 自分に移植する. 心臓だけフラスコの中で鼓動しているシーン. 最初はCGか何かかと思った.
#include <stdio.h> #include <array> std::array<int, 5> a = { { 3, 1, 4, 1, 9 } }; int main() { for (std::array<int, 3>::const_iterator i = a.begin(), ie = a.end(); i != ie; ++i) { printf("%d\n", *i); } }実害はないみたいだけど気持ち悪い(上記コードは5回ループする). VCだとサイズの異なるarrayのiteratorは違う型でエラー.
andがキーワードか否かを判別したかった話(解決編)
decimalbloatさんがやってくださいました. さすが.
#if not +0 #error "use -fno-operator-names" #endif
notが!なら!+0で1. notがキーワードでなければ定義されていないマクロは0になるというルールにより0+0で0. うまいな.
andがキーワードか否かを判別したかった話
C++ではandやorなどは実はキーワードで, たとえばdie()をメッセージを表示して終了する関数として
std::ifstream ifs("a.txt"); ifs or die("can't open");
なんてかけたりする. でも普通は使わない. ただXbyakではx86のニーモニックにandやorやxorがあるので関数名がバッティングしてしまう.
と言いつつVCではiso646.hをincludeしない限り, これらの名前は変数や関数に使える(規格違反だけど嬉しい). gccでは標準だと規格に従っていて, その機能を無効にしたい人向けに-fno-operator-namesというオプションが用意されている. だからそれを指定すればよいだけの話. なんだが, うっかり忘れたときのエラーが分かりにくい. たとえば
#include <stdio.h> int and(int a, int b) { return a & b; } int main() { printf("%d\n", and(3, 5)); }
は
t.cpp:3:5: error: expected unqualified-id before 'and' token t.cpp: In function 'int main()': t.cpp:10:20: error: expected identifier before '(' token
だ. できればもう少し分かりやすいエラーにしたい. 具体的にはC++11なら
static_assert(!なんとか::value, "use -fno-operator-names");
のように書いて, -fno-operator-namesが指定されてなければメッセージを出すようにしたい.
さて, 最初andとかは内部的に
#define and &&
みたいに書かれていてマクロの2回置換でandがdefineされているかどうかを見ればよいだろうと思った. けどandはC++ではキーワードでマクロではなかったのでその手は使えなかった(つまりその意味でVCのiso646.hの実装は規格に反してる. まあどうでもいいけど).
で, 結構頭を悩まして次のような方法を思いついた(自分で考えたい人は見ないように).
/* 定義 */ template<class T> struct X { enum { value = 1 }; }; template<> struct X<void (*)(int)> { enum { value = 0 }; }; /* 使い方 */ #ifdef __GXX_EXPERIMENTAL_CXX0X__ /* C++11のとき */ static_assert(!X<void (*)(int bitand)>::value, "use -fno-operator-names"); #else /* そうじゃないとき */ struct StaticAssert { // use -fno-operator-names options if the following code is error int use_fno_operator_names_option[X<void (*)(int bitand)>::value ? -1 : 0]; }; #endif
実はbitandも&の意味を与えるキーワードなのだ. だから規格準拠ならint bitandはint&とint参照の引数になり(この使い方は本来の意味と異なるけどありなのか?), bitandがキーワードで無かったら, 単なる仮引数となる. よって関数の型の違いでディスパッチできる.
/* エラー */ % g++ detect.cpp -std=c++0x -Wall detect.cpp:6:1: error: static assertion failed: "use -fno-operator-names" /* エラーでない */ % g++ detect.cpp -std=c++0x -Wall -fno-operator-names
本当はプリプロセッサの段階で判別したかったのだけど, それは無理だよねぇ?