Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

2009-12-31

成功の秘訣

8割近くの人は新年の目標達成できず、「成功の秘訣」を心理学者が指南。 | Narinari.com

まず、「失敗した」グループを分析したところ、浮かび上がったのは「自分の周りにある誘惑を取り除く」「模範的なお手本に沿って行動する」「自分の意思の力に頼る」という類の目標を立てた人が、失敗に陥りやすい傾向。しかも、「『もし成功することができなかったら…』と、悪い方向へ考える」人も多かったそうだ。

そして、研究を重ねたワイズマン博士は、「2010年に人々の生活を変えるのに役立つことを願う」と、10のアドバイスを伝授している。

  • 目標は1つだけにする。
  • 数日じっくり考える。
  • 以前立てた目標は避ける。
  • ごく普通の目標にする。
  • 細かくポイントを設定し、1つずつクリアしていく。
  • 自分にプレッシャーをかけ、サポートを得るために友人や家族に目標を話す。
  • 定期的に「達成するとどう好ましくなるのか」を書き出し、利点を考えるようにする。
  • モチベーションと進歩の感覚を守るため、1つのステップをクリアしたら自分にご褒美を与える。
  • 達成までの計画やプロセスを記録し、グラフや絵を使って分かりやすく示す。
  • 心が折れそうなときは諦めるのではなく、一時的に前の習慣に戻ったと解釈する。

興味深い。

C++プログラマのレベル10

レベル0

C++とかいう、Cにヘンテコな機能を付け加えた言語があることはしっているが、ワケ分からんので勉強する気にならない。

Cの何が不足なのか分からない。

レベル1

C++についてググったり、入門書を読んだりしてみる。文法はCに後から無理やり付け加えた感じだ。

でも文法がわかりにくすぎる。

レベル2

vectorとか便利すぎて涙がでる。もういちいちrealloc()を呼び出さなくてもいいんだ。でもイテレーターとかいうのが、ワケ分からんので、ポインタを使っている。

構造体の中に関数を書けるのは便利かもしれない。すくなくとも、わざわざ構造体のポインタを引数に渡さなくてもいいわけだ。

レベル3

テンプレートが分からなくて挫折中。テンプレートがわかれば、STLがもっと分かるようになる気がする。でも、いい参考書が見つからない。

継承とか仮想関数も便利だと気がつく。namespaceも地味に便利だ。

レベル4

ようやく、テンプレートについて解説している本やサイトを見つけた。

テンプレートコードの書き方を覚える。

レベル5

関数オブジェクトやイテレーターという概念を理解する。ようやくSTLをまともに使えるようになった。

先月書いた自分のC++のソースコードをみて、赤面する。

レベル6

日本語の参考書に見切りをつけて、洋書をあさる。C++ Templatesや、Template Metaprogrammingを読む。

ついに、テンプレートを完全に理解する。Dependant NameもTwo Phase LookupもArgument DeductionもSFINAEも理解する。

ADLは邪悪な機能だと気がつく。

先月書いた自分のC++のソースコードをみて、赤面する。

レベル7

メタプログラミングを理解する。覚えたばかりのメタプログラミングのテクニックや、Boostライブラリを使ってみたくて仕方がない。でも、職場がそれを許してくれない。

Boostの実装が知りたくてソースを読む。

C++の規格も、すこし読んでみる。

レベル8

仕事でBoostを遠慮なく使っても何も言われない。これはすなわち、以下のいずれかのケースを意味する。

  1. 数少ないC++を恐れることなく使う求人にうまくはまった。
  2. 高度なC++を教える仕事についた。
  3. 自分で立ち上げた会社なので、好きなコーディングルールを決められた。

レベル9

C++0xのドラフト規格を読む。C++0xのドラフト入りしている新機能について調べ始める。

C++について疑問が生じたら、まず規格を確認するようになる。

レベル10

C++界隈で自分の名前を知らない者がいない。知らない人から、「あ、先生。いつもC++でお世話になってます」と言われる。

C++WG JPのメンバーである。

レベル0xA

C++SCのメンバーである。

Bjarne Stroustrupとは、俺お前の仲である。

お断り事項

これは、C++の言語仕様を理解することに重点をおいたリストである。また、日本人限定である。C++で何か優れたソフトウェアを書いたということを意味するものではない。ただ、他のレベル10リストにインスパイアされたジョーク部分があるので、そのへんは、すこし変わっている。

C++WGに籍をおくというのは、かならずしも言語仕様を理解していることにはならない。というのも、実は、C++WGのメンバーになるために、C++の知識や経験などと言ったことはほとんど問われない。ただし、C++WGのメンバーになりたいと思った時点で、言語仕様については、それなりに理解しているはずであるし、相当の意欲があるはずだ。そうでなければ、C++WGの会議は苦痛でしかないだろう。

C++0x本は名詞を英単語で記述すべきか?

私は今、非常に斬新なアイディアを持っている。それは、来年書き始めるC++0x本の、専門用語の名詞を、すべて英単語で記述してはどうかということだ。

たとえば、lambdaやrvalueのような用語は、この英単語のまま書くことになるだろう。それなら、このルールを、すべての用語に広げてしまえばいいのではないだろうか。

広く普及した単語でも、おかしいと感じるものはたくさんある。例えば、式と文だ。これは、expressionとstatementの訳語だが、私は、式と文では、サッパリ意味が想像できない。

では音訳して、エクスプレッションとかステートメントというカタカナ化を行えばいいのではないかという意見もあるだろう。しかし、このカタカナ化は、かえって単語を分かりにくくする。

また、私の本は、C++0xを深く深く解説する本になる予定だ。読者対象は中級以上のプログラマである。初心者ではない。プログラミングというのがどういうものか知っていて、ある程度C++もかじっている人間である。そういう人間は、少なくとも、C++の専門用語に対する英単語ぐらい、知っているはずである。

type, function, class, pointer, reference.

例えば、上記の英単語に対する、一般的な訳語が分からないC++プログラマがいるだろうか。

動詞は、翻訳すべきだと思っている。たとえば、"a pointer A reference a variable B."という文章は、「variable Bを参照するpointer A」、「pointer Aはvariable Bを参照する」などと訳すことが出来る。「referenceする」という記述は、さすがに問題がある。

問題はある。関数とか変数とかコメントといった、極めて一般的になっている名詞まで、英単語にするべきなのだろうか。それぐらいは、例外を設けるべきではなかろうか。しかし、対象読者は、functionもvariableもcommentも、何を意味するか知っている。それに、たとえ知らなくても、C++0xの言語仕様を解説する本なので、functionというものがなにか、commentとは何か、ということも日本語で解説する。だいたい、プログラミングを全く知らないものが、関数とか変数という言葉を聞いても、プログラミングで使われている概念を悟るハズがない。数学の知識のある者は、関数や変数の概念を知っているという意見もあるかもしれない。しかし、数学でいう関数や変数と、プログラミング畑でいうものとは、やはり違うのである。とすれば、たとえ英単語で用語を記述したとしても、訳の分からない漢字で記述されているか、訳の分からないアルファベットで記述されているか、程度の違いしかないわけだ。

ところで、あくまで言語仕様を解説するので、明確に章節を分けると宣言したものの、まだ問題はある。gotoやswitch satetementと、labelを分けるのなら、まだいい。問題は、variableのdeclarationが、specifierという部類に属するのだ。これは、変数というものを説明するには、ものすごく回りくどい。さすがにまずかろう。

がしかし、考えてみれば、対象読者は、変数の宣言の書き方ぐらい、わかっていることを前提としている。それならば、彼らが知りたいのは、単に表面上の文法ではなく、言語として、どのように定義されているか、ではなかろうか。実際、私は、「どのように」書くかではなくて、「なぜ」そう書かなければならないのかを説明する本を書くと宣言した。それなら、規格書にそって説明するのも、無駄にややこしいというわけではない。

C++0xの本について考える

完全に言語として解説すべきかどうかが問題だ。

たとえば、lvalueとrvalueの違い、reference、move semanticsは、お互いに深く関係している。では、これらをひとまとめにして、同じ場所で解説していいものか。最初、厳密に分けるべきだと考えて、その後、思い直したが、やはり、厳密に分けるべきではなかろうか。

まず、move semanticsは、言語の機能ではない。むしろ、プログラミングのテクニックに属する。しかし、この前、rvalue referenceを完全に解説すると称して、そのような記事を書いたところ、少なからぬ人が、勘違いをしていた。どのような勘違いかというと、「std::move()に変数を渡したら、その変数は、それ以降は使えなくなるようだ」、「std::forward()は、template以外のコードでも使うのだろうか」などといった誤解である。

これは畢竟、move semanticsは、言語機能であると勘違いしているからなのだ。std::move()やstd::forward()とは、なにかコンパイラが生成する魔法の関数のように考えているのだろう。しかし、実際はcastでしかない。単なるreferenceへのcastなのだ。rvalue referenceで出来ることは、lvalue referenceでもできる。ただ、関数に渡したオブジェクトが、その関数内で勝手に破壊されたとあってはたまらないので、あまりそのようなコードが書かれないだけなのだ。rvalue referenceは、そのコードを安全に書くための方法である。

また、std::forward()に関して。これは、templateのargument deductionがあるために、必要なのだが、誤解している人は、argument deductionについてよく知らないから、誤解しているのだ。Bjarne Stroustrupはインタビューで、普通のプログラマが、std::move()やstd::forward()の実装について理解している必要はないと言った。しかし、std::forward()の実装を知らないが、templateのargument deductionは完璧に理解しているという、普通のプログラマがいるのだろうか。

とすれば、この三つの項目は、完全に章節を分けて、分離したほうが良い。純然たる概念と、言語機能と、テクニックは、別物である。lvalueとrvalueの違いについては、言語の基本的な概念である。referenceは、言語の文法である。move semanticsは、プログラミングのテクニックやライブラリに属する。

このように厳密に分けることは、「細かいことなんてどーでもいーから、さっさとmove semanticsとやらを使いたいんだよ。コードが速くなるって聞いてるしな。最適化のためなら何だってやるぜ」という類のプログラマの不評を買うだろう。そうでなくとも、読者は「なお、この機能に関係のある某機能については何章を参照されたし」という記述を見て、飛び飛びに読まなければならない。それでも、誤解を招くよりはいい。

すでに世に出回っている、パーフェクトC#という本は、goto statementと、goto statementに使うlabelを、別々に記述していた。これは私の、厳密に分けるという理想を後押しする。厳密に分けるのが、最も正しい記述法であると信ずる。結局、これは入門書ではないのだから。

用語の問題だ。私は今、下手に訳さずに、アルファベット表記することを、本気で思案している。

たとえば、referenceの一般的な訳語は、参照だ。しかし、これで意味が分かるだろうか。みな、「サンショー」という音だけで覚えているのではないか。「pointerは変数を参照する」というような記述は分かる。この場合の参照は、日本語として機能する。ところが、「この機能は、参照という名前である」という記述は、わけが分からない。だったら、「この機能は、referenceという名前である」でもいいのではあるまいか。

就中、今回のC++0xには、constructorのdelegationやら、exception propagationやら、実に翻訳に困る概念がたくさん入っている。デザインパターンの世界では、delegationを、委譲と訳しているようだが、どう考えても、addressを番地と訳すのと同じぐらい泥臭い訳である。

ただし、アルファベット表記にも問題がある、ポインタとか、キャストなどといった、もう十分浸透しているだろうというような単語にまで、これを適用するのは、だいぶ難しい。この文章では、実際にそのような記述をしてみた。ただし、関数とかオブジェクトのような言葉は、さすがにやめておいた。

「instantiationする」ならまだともかく、「castする」という言葉は、どうも違和感がある。第一、これを厳密に、全文に適用するならば、「pointerを参照する」という文章にしたって、「pointerをdereferenceする」となってしまう。ここまでするぐらいなら、英語で書いた方がマシではあるまいか。

ひとつ思うのは、この文章は、動詞だからまずいのではないかということだ。つまり、サ変活用を、「英単語+する」などと使うからまずいのではあるまいか。名詞は英単語にしておいて、動詞だけ訳すというのはどうか。現に、「reinterpret_castでpointerを数値にキャストする」という文章なら、全く問題なく読めるはずだ。

しかし、delegateや、instantiateのような動詞は、依然として訳しづらい。「デリゲートする」、「インスタンシエイトする」という文章で、通じるだろうか。少なくともdelegateについては、「委譲する」などという奇妙な日本語より、マシだと思うのだが。

あのイケメンのアキラさんの書いた、C++ テンプレートテクニックでは、「インスタンス化する」という表現を用いている。たしかに、化という接尾語は、ニュアンス的にもわかりやすい。

しかし、これにも例外を設けなければならない。関数、変数などといった有名な言葉は、さすがにこのルールを適用するのは難しい。

私がこのようなことを考えるのは、単に用語の翻訳の難しさから逃げるためばかりではない。思うに、技術者というのは、英語が使えなければならない。海外のフォーラムやIRCでは、boostをいとも当然のごとく使っているのにも関わらず、国内では、STLさえまともに使えないC++プログラマがいる。これは結局、日本語のドキュメントに乏しいからだ。結局英語を使わねばならぬのだとしたら、英単語に慣れていた方がいいのではなかろうか。プログラミング関係の英語は、小説のように難しい表現など出てこない。単語さえ知っていれば、分かるのである。

rvalue Reference is not an rvalue

rvalue referenceは、rvalueではない。私は今まで、これを深く考えたことはなかった。一体どういうことなのか。

int a ;

// Error
int && b = a ;

// OK. the same thing std::move() does.
int && c = static_cast< int && >(a) ;

// Error. Why?
int && d = c ;

bはエラーになるのは、常識でも理解できる。しかし、なぜdがエラーになるのか。まったく同じ型ではないか。また、こんな例もある。

// lvalue reference
void f( int & ) {}
// rvalue reference
void f( int && ) {}

int main()
{
    int x = 0 ;
    int && ref = std::move(x) ;

    // calls lvalue reference overload of f()
    f(ref) ;
}

なぜだろうか。rvalue referenceを渡しているのに、lvalue referenceのオーバーロードが呼ばれるとは、不思議である。さっそく、規格にあたろう。

8.5.3 References [dcl.init.ref] p5に、以下のように書いてある。

Otherwise, ... or the reference shall be an rvalue reference and the initializer expression shall be an rvalue.

rvalue referenceは、rvalueで初期化しなければならない。ところで、rvalue reference自身は、rvalueではない。lvalueである。よって、rvalue referenceを、rvalue referenceで初期化することは出来ない。

やれやれ、これで、C++0x本を書くときは、正しく説明することが出来る。自分でも、いまいちこの辺を理解していなかったので、ref-qualiferの説明のさいに、コードを間違えてしまったのだ。

2009-12-30

テスラコイルによるゼルダの伝説のテーマ

これはかっこいい。

人間の脳は信用できない

私は以前、3DCGの描画技術の進歩の価値を疑う動画において、いかに人間の脳が、補完能力に優れているかを示した。今回、似たようなコンセプトの画像を発見した。

⊂⌒⊃。Д。)⊃カジ速≡≡≡⊂⌒つ゚Д゚)つFull Auto | こういう画像のストックどんどん増やしてこうぜww

リンク先は、Safe For Workであるハズである。しかし、これはすごい。結局、人間の脳が、都合よく補完してしまうのだろう。

もはや、私には人間の脳を信用することは出来ない。

2009-12-29

用語の翻訳は難しい

専門用語の必要性

最初に方程式と訳した者を尊敬する・・・
通じないかもしれないのにな・・・
ただの幸運なバカがたまたま使ってみたら大丈夫だったのか・・・?
それとも・・・訳語の必要性に追いつめられた必死さが切り開いた発明なのか?

用語の翻訳は難しい。ある単語を、長文を費やして、別の言語で説明することは簡単だ。たとえば、方程式は、wikipediaの文章によると、「さまざまな対象の間に成り立つ数学的な関係を記号を用いて等式などの式によって表したもの」となっている。しかし、わざわざ毎回こんな長文を使うのは、甚だ面倒である。よって、我々には、お互いの了解しあえる、短い単語が必要である。

しかし、「等式など」という言葉には引っかかる。方程式は、等式以外も含むのだろうか。方程式の英語の訳語としては、どの辞書でも、Equationであるが、これは文字通り、等式である。考えてみると、方程式が、等式だけを意味するのかどうか、その名前だけでは、いまいち分からない。あるいは、方程式をequationと訳すのが間違っているのだろうか。そう考えると、方程式とは、あまり適切な用語では無いのかもしれぬ。

話がそれた。本来、方程式という言葉を云々する予定はなかった。しかし、用語の翻訳の難しさは理解してもらえたと思う。

用語は必要である。我々は数学を論ずるとき、方程式という言葉を、お互いが了解しているものとして使う。わざわざ、長文を用いたりしない。

しばしば、「技術者は専門用語を使わずに、一般人にも分かりやすく話すべきだ」という批判を聞く。分かりやすく話すべきなのは、もちろんなのだが、専門用語を使わずに話すのは、非常に面倒なのである。例えば、

数学者A、「それでね、この「さまざまな対象の間に成り立つ数学的な関係を記号を用いて等式などの式によって表したもの」Aと、「さまざまな対象の間に成り立つ数学的な関係を記号を用いて等式などの式によって表したもの」Bを使ってだね」
数学者B、「いや、それは計算が甚だ面倒だ。実用に足る近似値は、「さまざまな対象の間に成り立つ数学的な関係を記号を用いて等式などの式によって表したもの」Cでも計算できる」

数学者A、「それでね、この方程式Aと方程式Bを使ってだね」
数学者B、「いや、それは計算が甚だ面倒だ。実用に足る近似値は、方程式Cでも算出できる」

主婦A、「あらあら、お隣の奥さん。ちょっと聞いてちょうだいよ。向こうのスーパーでね。今日はね。「ニワトリという動物のメスが卵細胞や、多少発生(→胚発生)が進んでも見かけ上それがわからない状態で体外(外環境)へ産み出すもの」が安かったのよ! 「ニワトリという動物のメスが卵細胞や、多少発生(→胚発生)が進んでも見かけ上それがわからない状態で体外(外環境)へ産み出すもの」が!」
主婦B、「あらまぁ、ほんとぉ? でもねぇ、あいにくと、「ニワトリという動物のメスが卵細胞や、多少発生(→胚発生)が進んでも見かけ上それがわからない状態で体外(外環境)へ産み出すもの」はおととい、たくさん買ってしまったのよぉ。残念ねぇ」

主婦A、「あらあら、お隣の奥さん。ちょっと聞いてちょうだいよ。向こうのスーパーでね。今日はね。タマゴが安かったのよ! タマゴが!」
主婦B、「あらまぁ、ほんと? でもねぇ、あいにくと、タマゴはおととい、たくさん買ってしまったのよぉ。残念ねぇ」

このように、共通の用語がない場合、文章や会話は、非常に分かりにくいものとなってしまう。専門用語を廃した結果、よりわかりにくくなってしまうとは皮肉である。

つまり我々には、専門用語が必要である。しかし、方程式やタマゴのように、すでに一般に知られている用語ならともかく、まったく新しい事柄に対する専門用語は、どのように発明すればいいのだろうか。

C++0xの用語

C++0xには、様々な新機能が追加されている。そして、新機能を言い表す、簡潔な用語がある。しかし、その用語は、英語である。C++0xの日本語の本を書くからには、この用語を、どのように表記するかという問題がある。

用語は、一人の天才によって決まるわけではない。もちろん、きっかけを作る人間はいるが、結局、最もよく使われている言葉が、自然に選ばれるようになるのである。

たとえば、"address" という用語がある。現在一般的な訳語は、「アドレス」である。ところが、一昔前のプログラミングの本を開くと、しばしば「番地」という用語が見受けられる。アドレスというのは、音訳である。その発音を自国語の文字で表現する訳しかたである。番地というのは、和訳である。これは、非常にセンスを問われる。

これ以外に、訳さないという選択もある。すなわち、"address"というアルファベットの表記を、そのまま用いるのである。これを、今仮に、「原語」と呼ぶことにする。

音訳、和訳、原語、どれが最適なのかは、一概に決定できない。

C++には、"reference"という用語がある。現在、もっとも広く使われている訳語は、「参照」であると思われる。しかし、私はこれには、少し問題があるとおもう。

int x ;

// a pointer p reference x.
int * p = &x ;

// dereference p.
*p ;

// a reference r reference x.
int & r = x ;

これを日本語に訳すと、どうなるだろうか。

int x ;

// ポインタpは、xを参照している。
int * p = &x ;

// pを参照する。
*p ;

// 参照 r は x を参照している。
int & r = x ;

referenceの名詞、動詞、dereferenceは、すべて参照、あるいは、参照のサ変活用で訳される。これは、どうも分かりにくいと思う。私は、名詞としてのreferenceは、referenceをそのまま使うか、リファレンスと訳してもいいのではないかと思う。しかし、すでに参照という訳語が定着しているのも、また事実である。参照、リファレンス、reference、どれがわかりやすいだろうか。

C++0xでは、ただのreferenceというものはなくなり、それぞれ、lvalue reference、rvalue referenceと呼ぶようになる。単にreferenceと行った場合は、その両方を指す。

ここで、lvalueとrvalueを、左辺値、右辺値と訳すのは、C++においては、適切ではない。C言語ならば、それで正しかったが、C++では、左辺、右辺とは、なんの関係もないからだ。したがって、C++のrvalue referenceを、「右辺値参照」などと言っている人間や書籍は、信用してはいけない。その人は、lvalueとrvalueが何を意味するのかもわかっていないのである。しかし、lvalue/rvalueを、一体どう訳せばいいのだろうか。

音訳すると、エル・バリュー、アール・バリューになる。これはあまりにもひどい。L値、R値と訳すべきか? これも分かりにくい。

結局、私の考えとしては、lvalueとrvalueとは、そのままアルファベットで表記するしかないように思える。とすると、rvalue参照、rvalueリファレンス、rvalue referenceの、三つの翻訳候補ができあがる。どれがわかりやすいだろうか。

referenceは、まだマシである。lambdaとなると、完璧に新しい事柄なので、非常に難しい。訳語は、無名関数、ラムダ、lambdaのどれかになるだろう。私はlambdaが最適だと思うが、これは畢竟、私が多少なりとも英語をかじっているから、そう思うのかもしれない。英語と数学の知識がまったくない人間にとっては、無名関数が一番わかり易いだろう。さらに、lambda-introducerとなると、さらに難しい。

実を言うと、私は、派生クラス、基本クラスという用語も、気に入っていない。C++では、derived class、base classという用語が用いられる。これを、派生、基本と訳すのはどうも気に入らない。一般にオブジェクト指向では、サブ・クラス(sub class)、スーパークラス(super class)という用語が用いられるのだが、なぜC++では、元々の英語からして、このような用語を使うのだろうか。その理由の一端に、他ならぬBjarne Stroustrup自身が、サブクラスとスーパークラスとで、どっちがどっちだか、よく迷うからという理由があった。これは、本人がD&Eで告白している。

The names derived and base were chosen because I never could remember what was sub and what was super and observed that I was not the only one with this particular problem.

derived(直訳:派生)とbase(直訳:基本)という名前は、私が、どちらがサブで、どちらがスーパーなのか、一度も覚えられた試しがなく、またこの問題のあるものは、私だけではなかったという理由で、選ばれた。

Bjarne Stroustrup, The Design and Evolution of C++, section 2.9

確かに、私個人としても、サブとスーパーはよく分からない。なんとなく、スーパーの方が強そうだから、スーパークラスはサブクラスを継承するものではないか、と思うことがよくある。

してみれば、他ならぬBjarne Stroustrup自身も、用語に困っているわけである。

話を元に戻すと、derived、baseをそれぞれ、派生、基本と訳すのは気に入らないが、少なくとも、どっちがどっちかという疑問を起こすことはないと思う。したがって、これはまだマシな訳語であると思う。

テンプレート周りの用語は、さらに厄介である。例を挙げるだけで、考察はしないが、Instantiation、Two Phase Lookup、Argument Deduction、Depandant Name、等々。テンプレート以外でも、まだ考察すべき用語は沢山あるが、用語の一覧を作るのが目的ではないので、この辺でやめておく。

私の執筆する予定のC++0x本では、これらの用語を使うし、意味も解説する。これは絶対に書く。いやしくもパーフェクトなどと冠したC++0x本で、これらを解説しないという事はありえない。

ついでに言うと、私はパーフェクトなどという本のタイトルも気に入っていないが、それはまた別の話である。タイトルは私が考えたわけではないので、どうか私を責めないでもらいたい。

結論

結局、用語の翻訳には、音訳、和訳、原語をそのまま使うという、三つしかない。今考えているのは、仮に音訳か和訳を使うとしても、必ず一度は、原語を併記するというものである。

ひとつ恐れていることとしては、私は英語を知っているということである。私は無意識のうちに、英語を知っていることを前提にした文章を書いてしまわないかという懸念がある。

私は少なくとも、規格書を読める程度には、英語を知っている。もちろんこれは当然のことで、現時点でC++0xの本を書くとなれば、規格を読めなければならない。個人的に、すべてのプログラマは英語の読み書きが出来るべきであると考えている。もし私が、自分の為にパーフェクトなC++0xの本を書くとするならば、当然、英語で書く。その方が余計な苦労をしなくてすむからである。多くの有名なライブラリは、ドキュメントが英語で書かれている。英語が読めなければ使えない。誰かが翻訳してくれるのを、他力本願で祈るしかない。

ところが、現実はそうではない。世の中には、英語を知らないプログラマがたくさんいる。私はかつて、ある会社の求人の面接に行ったが、
「プログラミングに最も大事なことはなんであると思いますか?」
という問に対して、
「英語です。プログラミングというのは、自分で実装するよりも、むしろライブラリを使うことが多いと思いますが、有名なライブラリのドキュメントは、英語で書かれているものが多いのです。したがって、最も必要なものは、英語の読解力だと思います」
と答えたところ、面接担当のひどく肥満した大阪人の中年のプログラマに、
「ヘェー、そーなん。ボカァ、英語なんてさっぱり分からないんやけど。ナハハハハハ」
と笑われたことがある。現実はそんなものである。

ちなみに、その会社は、関数を使わずmainに全部書けば、一番早くなるとも言っていた。彼らは、コードもCPUのキャッシュを圧迫するということを知らないらしい。ちなみに、その会社は、組み込み系特化というわけでもなかった。

世の中にはこの程度の認識のプログラマが多い。思うに、これは、本人が悪いのではない。参考書が悪いのである。特に、日本語で書かれたC++の本は、たいがい、あまりよろしくない。私は今まで、あまりにもひどい参考書を、腐るほど見てきた。全くの誤解を書いているものもあれば、あるひとつのプラットフォームにおける話を、すべてのプラットフォームに拡大出来るものと信じている本もあった。私の本は、これらの悪書の轍を踏まぬようにしなければならない。あくまで純粋な言語としてC++を解説し、環境依存の話は、できるだけ避け、またどうしても書かなければならない場合にも、環境依存であることを明記するつもりである。

私が書く予定のC++0x本の対象読者は、もちろん日本人のプログラマである。私は英語を知らない日本人に理解出来るように、日本語で書かなければならない。これは英語で書くより難しい。

2009-12-28

NSFW これはすごいjavascriptの使い方

リンク先、ポルノサイトの為、注意。

The Rainbow Of Porn

これはすごい。画像のどこでもいいからクリックすると、その色のエロ動画を表示してくれる。

これは、別に技術的には、それほど面白いものでもない。Javascriptで、クリックした場所の色を取得。その色とよく似たサムネイルのエロ動画を探すだけだ。ただ、この発想はすごい。

via: イメージ画像をクリックすると、その色と似た色のポルノ映像がどわーんと現れる検索サイト「The Rainbow Of Porn」:ザイーガ

面白い動画をふたつ

2009-12-27

曹操の骨、発見さる

「三国志」曹操の陵墓発見 中国河南省、遺骨も出土 - 47NEWS(よんななニュース)

【北京共同】中国中央テレビによると、中国河南省文物局は27日、同省安陽市安陽県で、後漢末期の武将で三国時代(3世紀)の魏の基礎をつくり、「三国志の英雄」として知られる曹操(155~220年)の陵墓を発見したと発表した。

 陵墓からは60歳前後とみられる男性の遺骨が見つかり、専門家による暫定的な鑑定結果によると、60代で死亡した曹操本人のものとみられるという。曹操の陵墓の所在地をめぐっては諸説あり、これまで特定されていなかった。今回の発見で、曹操に関する謎が解明されるのではと期待されている。

 陵墓は面積約740平方メートル。二つの墓室などがあり、鉄剣や水晶、石碑などの埋葬品が200点以上出土した。曹操を示す「魏武王」と刻まれた銘文も含まれ、曹操の陵墓だと示す根拠の一つになったという。

 曹操とみられる男性のほか、女性2人の頭蓋骨や足などの遺骨も見つかった。

 同陵墓は誰を埋葬したものか分かっていなかったが、盗掘などが相次いでいたため、文物局が昨年12月から、盗掘防止のための発掘作業を進めていた。

なんだって? 曹操の骨だと?

曹操は素晴らしい漢詩を残した。曹操を超える詩人は、中国に存在しない。いや、白居易や韓愈がいるか。

ニュー速では、早速、歴史オタと三国志オタと横山光輝三国志オタと漢詩オタが沸いている模様。

また、公開されている碑文の写真をもとに、曹操の墓にいれる碑文としては、彫りが荒いとか、竹簡に書く人が持つ引きグセが少ないから、紙に字を書いていた人の字を起こしたのだろうとか、全くついていけないことが語られている。

冷静に考えたら

規格書通りの目次というのは、やはりよろしくない。結局、そんな飛び飛びに物事を説明している本を読むぐらいなら、規格書を読めばいいのだ。すべてのプログラマが規格書を読むべきというのは、理想だが現実的ではない。だから参考書というものが必要ではなかったか。

たとえば、前回の例でいうと、lvalueとrvalueの違いを説明するのはもちろんのことだが、これ単体で説明するより、参照の部分で説明した方が、わかりやすいだろう。バラバラに配置してある説明を、たらい回しのように追いかけて読んでいくのは、電子媒体でも面倒なのだから、物理的な紙の本なら、なおさらである。また、gotoの部分で、ラベルの記述法を説明しないというのは、あまりにも馬鹿げている。

ともかく、今は闇雲に妄想したり、無計画に一部分だけ書き出したりするのではなく、より深く規格を理解することに努めよう。例外周りは、あまり知らない。新しく付け加えられた、スレッドを超えて例外を投げるとか、例外のネストという機能は、ライブラリで実装されている。使い方はそれほど難しくないのだが、やはり実際に試せる環境がないのがつらい。

実際に試せる環境がないというのは、実につらい。もちろん、文法や挙動などは、規格を読めば分かる。しかし、実際に書いたコードが、well-formedかどうかは、人間が確かめるのは無理なのだ。例えば、タイプミスをしているかもしれない。そういうエラーは、人間はまず発見できないと思うべきである。

賢い金魚

投稿者のコメントを翻訳。

犬を飼ってない? 金魚に「取ってこい」をしつけよう。このしつけをするためには、餌やり棒とフープが必要。どっちとも、自作できるよ。

  1. 金魚がフープに近づいたら餌をやる
  2. 金魚が頭をフープにかぶせたら餌をやる
  3. 金魚がフープを動かす距離を、少しづつ長くしていく
  4. フープを持っていく場所を変えないようにする

このしつけを覚えさせるためには、何日も何回も訓練が必要。時には、金魚が何かするまで、辛抱強く長時間待ってなくちゃなんない。

水が緑色なのは、藻の繁殖のせい。藻はとても小さい緑色の植物で、金魚のエサになるし、毒じゃない。金魚のだす尿をきれいにしてくれる。

また、ペットショップで展示している水槽の水がきれいなのは、客に金魚を見せるためと、業者はたいてい、強力なフィルターを使っているから。

C++0xの本について

C++0xの本を執筆する予定である。詳しいことは何も決まっていない。出版社は技術評論社で、タイトルは、現時点では、「パーフェクトC++0x」ということになっている。技術評論社は、すでに「パーフェクトC#」、「パーフェクトJava」を出しており、今回、そのC++版を出したいらしい。

昨日、参考として、すでに刊行されている二冊の「パーフェクト」シリーズが、無料で自宅に送られてきた。だいぶ分厚い本である。ただ、C++も、真面目に書こうとすれば、これだけ分厚くなることは間違いない。

しかし、パーフェクトとは、またずいぶん気負ったタイトルである。「C++入門」でも、「はじめてのC++」でも、「サルでもわかるC++」でもないのだ。

思うに、プログラミングということには、二種類あるとおもう。プログラミング言語の文法と、プログラミングの本質的な概念(変数、条件分岐、ループ、サブルーチン、その他アルゴリズム等)とだ。よく、「ひとつのプログラミング言語を学べば、他の言語は、さほど苦労せずに覚えられる」と言われているのは、この後者、つまりは、文法とは離れた本質的な概念を理解しているから、これを学び直す必要がないので、その分、苦労しないのだと思う。必要なのは、言語の文法を覚えるだけである。

プログラミングの完全なる初心者は、この二種類のどちらも分からない。したがって、初心者用のプログラミング教本は、この二種類を並行して教えなければならない。

私が書きたいのは、言語の文法に特化した本だ。もちろん、テンプレートを用いた、ジェネリックでメタメタなアルゴリズム本も興味はあるが、それは書くなら別の本だ。さらに、「どのようにして」コードを書くか? ではなく、「なぜ」コードをこのように書かなければならないのか? という疑問に答える本にしたい。世の中には、プログラミング言語の理解が十分ではなく、適当に書いてコンパイルし、コンパイラがエラーを出したから、このコードは誤り、これはコンパイルが通ったから、正しい、などと結論する種類の人間がいる。そういう人が、「言語の文法とは、こうなっていたのか」と理解できるような本にしたい。

テンプレートを解説している本はいくつもある。特殊化、部分的特殊化、テンプレート・テンプレート引数(Template template arguments)までを解説している本は、いくつもある。しかし、それだけでは、テンプレートを理解するには足りない。Argument Deductionについて知らなければならない。Dependant Nameについて知らなければならない。Two Phase Lookupについて知らなければならない。SFINAEについて知らなければならない。私はこれらも含めて、C++を解説する本を書きたい。

パーフェクトシリーズを読むと、幸い、これは完全な初心者に向けた本ではなさそうである。項目ごとに、独立して書いてもよさそうだ。

問題は、どのようにすれば、C++の言語仕様を、もらさず書けるのだろうか。ひとつ思い浮かんだのは、規格書の目次の通りに書くというのはどうだろう。

これには問題もある。まず、本を1ページ目から逐次読んでいくようには書けない。むしろ、調べたい項目を目次や索引で探して読む、辞書になってしまうだろう。

そういう本はあまりみたことがない。第一、問題がある。

たとえば、Rvalue referenceの場合、Rvalue referenceだけを解説し、Move Semanticsは、章を分けて、ライブラリ側で記述することになる。rvalue referenceとmove semanticsは一緒にしておいた方が、短期的にはわかりやすい。しかし、分けるのは妥当だと思う。というのも、Move Semanticsという言語機能はないからだ。言語に機能として存在するのは、Rvalue referenceだけである。Move Semanticsというのは、誤解を恐れず言えば、rvalue referenceを、オブジェクトがmove可能かどうかという、フラグとして利用するだけなのだ。

たとえば、switchとgotoの場合、解説が飛び飛びになる。gotoで飛ぶべきラベルは、ラベル・ステートメントの中で、caseやdefaultと一緒に説明される。switch自身は、セレクション・ステートメントの中の、switchステートメントで解説される。goto自身は、ジャンプ・ステートメントの中の、gotoステートメントで解説される。これはさすがに、文法上は正しいとしても、解説が飛び飛びになってしまって、わかりにくいかもしれない。

規格書の、コア言語部分と、言語に近いライブラリをあわせても、500ページぐらいだと思う。もちろん、規格の翻訳書にするつもりはないので、ページ数が合うことはないだろうが、書ける量ではないだろうか。

いまあるぼんやりとした案では、コア言語機能と、言語に近いライブラリ(atomicやthreadなど)は、一通り解説したい。ライブラリは、イテーレーターやコンテナ、関数オブジェクト、メタ関数などといった、ライブラリを使うにあたって、本質的に必要な概念を説明したい。ライブラリの詳細を細かく深く解説するというのは、できれば、本を分けるべきだと思う。

いずれにせよ、まだ何も決まっていない。それに、執筆にはかなり長い時間がかかる。

現実的に切実な問題としては、当面の生活費をどうするかという実に個人的な問題もある。技術書は、金にはならないだろうし。

レゴの家

完全にレゴでできた家。水回りは最悪。カミソリはポロッと落ちる。体をこする洗面用具は、あまりお肌に良さそうではない。床は足つぼを非常に良く刺激する。

2009-12-26

関数の宣言の順序

ふと、こんなつぶやきを聞いた気がする。

struct foo { auto f()->int && { ... } }; って、int f() && か、int && f() のどっちに解釈されるの?

誰がつぶやいたのか覚えがないが、同時に、「プリプロセッサたんは俺の嫁」というつぶやきも聞いた気がする。不思議なことだ。一体誰がつぶやいたのだろう。それに、俺の嫁はUnified Function Sytanx(統一関数文法)たんに決まっている。New function declaration syntax(新関数宣言文法)たんでは、断じてない。

それ以降、つぶやきは聞こえなくなってしまった。おそらくは自力で問題を調べ、わざわざ答えをつぶやくまでもない、しごく簡単な疑問だということに気がついたのだろう。結論から言うと、

struct foo
{
    auto f() ->int && ;
} ;

この新しい関数宣言の記法を使ったコードは、従来の関数宣言の文法を使えば、

struct foo
{
    int && f() ;
} ;

このように書くことが出来る。一方、*thisへのref-qualiferを指定したければ、

struct foo
{
    auto f() && -> int  ;
} ;

このようになる。理由は簡単明白だ。規格をちらと見ただけで、見逃しようもないほどはっきりと書いてある。

In a declaration T D where D has the form

D1 ( parameter-declaration-clause ) attribute-specifieropt cv-qualifier-seqopt ref-qualifieropt exception-specificationopt trailing-return-type

and the type of the contained declarator-id in the declaration T D1 is “derived-declarator-type-list T”, T shall be the single type-specifier auto.

つまり、順番がわかりやすいように、全部を使ってメンバ関数を長々と書くと、以下のようになる。

struct foo
{
    auto            // T はautoでなければならない。
    f               // 関数の名前
    (void)          // 引数リスト
    [[]]            // attribute
    const volatile  // cv-qualifier
    &&              // ref-qualifer
    throw()         // exception specification
    -> int &&       // 戻り値の型
    ;               // expression-statementの終端記号
} ;

これを、従来の関数の文法と比べてみると、以下のようになる。

// 従来の文法
int && f(void) [[]] const volatile && throw() ;

// 新文法
auto f(void) [[]] const volatile && throw() -> int && ;

ちなみに、Unified Function Syntaxが可決された暁には、autoが[]になる。

[] f() -> int ;

Unified Function Sytanxは、とても素晴らしいので、是非とも規格入りしてもらいたい。

C++0xの新機能のリスト

どうやら、C++0xの本を執筆することになった。

ふと思えば、今まで一度も、C++0xの新機能がどのくらいあるのかということを考えたことがなかった。規格の変更は、もちろん大量にあるのだが、その中で、特に知っておくべき変更や追加というのは、どのくらいあるのか。整理するために、リストアップしてみた。このリストに載っていない機能や、既存の規格に対する変更で、特にユーザーも知っておくべきものがあれば、知らせて欲しい。

C++0xはまだドラフト段階だが、確実にこれは大きく変わらないだろうという機能は、かなりある。逆に、これはちょっとまだ分からないという機能もある。

言語機能

  • Rvalue Reference
  • auto
  • delctype
  • static_assert
  • Template Aliases
  • extern template
  • Variadic Templates
  • Initializer lists
  • Strongly Typed Enums
  • constexpr
  • inline namespace
  • attribute
  • alignment
    (alignof, aligned_storage, aligned_union, Alignment attribute)
  • Extending move semantics to *this
    (ref-qualifer for non-static member functions)
  • Making Local Classes more Useful
    (local class can be used as template arguments)
  • Extended friend Declarations
    (allows template argument to friend declaration)
  • Delegating Constructors
  • Explicit Conversion Operators
  • New Character Types in C++/UTF8 Literals
    (u8"...", u"...", U"...")
  • Universal Character Names in Literals
  • Right Angle Brackets
    makes std::vector< std::vector<int>> valid.
  • Default template argument for function template
  • Inheriting Constructors
  • lambda
  • Raw String Literals
  • Extending sizeof to apply to non-static data members without an object
  • Defaulted and Deleted Functions
  • Unrestricted Unions
  • Non-static data member initializers
    (allows initialization of non-static member variable with assign)
  • Forward declaration of enumerations
  • New function declaration syntax for deduced return types
    (maybe replaced by Unified Function Syntax)
  • Thread-Local Storage
    (should be explained with thread library)

言語機能に近いライブラリ

  • Move semantics
  • Adding extended integer types to C++.
    (<cstdint>)
  • thread
  • atomic
  • Exception Propagation
  • nested_exception
  • type_index
  • initializer_list
    (should be explained with core language feature)
  • type_index

ライブラリ

  • type traits
  • System error support
  • Compile-time rational arithmetic
  • Tuples
  • Function objects
    function, bind, ref, hash etc.
  • allocator
  • Time utilities
  • Container
    unordered associative containers and other changes.
  • Algorithms
  • Numerics library
    random, Generalized numeric operations, C Library etc...
  • Regular expression library

たぶん解説した方が良い項目

  • Synchronizing the C++ preprocessor with C99
    (steals C99's useful but ugly and evil preprocessor feature)
  • Changing Undefined Behavior into Diagnosable Errors
    for "if the Integer literal cannot be represented as a long int", "If the character following a backslash is not Character Escapes", and "Passing Non-POD Objects to Ellipsis"
  • Adding the long long type to C++
    (ugly way to declare 64bit integer for the sake of C99 compatibility)
  • Proposed addition of __func__ predefined identifier from C99
  • Reserved namespaces for POSIX
    just a reserved namespace. no more.
  • user defined literals
    (personaly I don't like it.)

現行ドラフトにまだ入っていないか、不安のある項目。

  • Unified Function Syntax
  • range-based for
    (drop of concept may affect this. current draft use ADL. A bit unstable I guess.)

現行C++と、表面上はほとんど変わっていないが、解説すべき項目

  • class
    (grammer)
  • template
    grammer, Name(Dependant name), Instantiation(Two phase lookup), Argument deduction, SFINAE
  • meta programming
  • Function Object
  • Iterator
  • ADL
  • overload resolution

2009-12-25

ref-qualifier: rvalue referenceの完全を期すための補足

rvalue reference 完全解説で、rvalue referenceは、ほぼ解説した。ところが、うっかりしたことに、ひとつだけ忘れていた事項があったので、それを解説する。

それは、非静的なメンバ関数に、ref-qualifierがつけられるというものだ。例を挙げる。

struct Foo
{
    void f() & {}
    void f() && {}
}

いったいこれは何なのか。これは、thisに対する修飾である。thisは、C++では、歴史上の理由でポインタになっているが、本来、参照となるべきであった。thisが指し示すのは、そのクラスのオブジェクトである。

struct Foo
{
    void f() {}
} ;



int main()
{
    Foo a, b ;

    a.f() ;// thisは、aを指す。
    b.f() ;// thisは、bを指す。
}

つまり、非静的なメンバ関数には、暗黙の内に、thisという引数が渡されていると考えても良い。実際、規格上は、そのような扱いになっている。というのも、thisもoverload resolutionの際に考慮されるのだ。C++03では、非静的なメンバ関数には、cv修飾ができる。これはなんに対する修飾かというと、thisに対する修飾である。

struct Foo
{
    void f() { std::cout << "none" << std::endl ;}
    void f() const { std::cout << "const" << std::endl ;}
    void f() volatile { std::cout << "volatile" << std::endl ;}
    void f() const volatile { std::cout << "const volatile" << std::endl ;}
} ;



int main()
{
    Foo a ; Foo const b ;
    Foo volatile c ; Foo const volatile d ;

    a.f() ;// none
    b.f() ;// const
    c.f() ;// volatile
    d.f() ;// const volatile
}

コンパイラは、thisのcv修飾(cv-qualifier)を静的に決定できるので、当然、このoverload resolutionも、静的に解決出来るのである。

今回、これに参照修飾(ref-qualifier)が加わる。以下のように使える。

struct Foo
{
    void f() & { std::cout << "*this* is lvalue reference." << std::endl ;}
    void f() && { std::cout << "*this* is rvalue reference." << std::endl ;}
} ;

// 関数の戻り値はrvalue
Foo g() { return Foo() ; }


int main()
{
    Foo a ;

    a.f() ;// lvalue reference.
    std::move(a).f() ;// rvalue reference.

    g().f() ; // rvalue reference.
}

コンパイラは、ある型がlvalueなのかrvalueなのかを、静的に決定できるので、当然、overload resolutionも静的に決定出来るのである。

ちなみに、何も書かないと、lvalue reference修飾したものとみなされる。

もちろん、cv-qualifierも、メンバ関数の型として扱われるので、同名で引数が同じメンバ関数の型は、8種類あることになる。cv-qualifierとref-qualifierは、どちらもoverload resolutionの際に考慮される。

たぶん、これでrvalue refereneに対する解説は、完全になったことと思う。

2009-12-24

safariのアップデートを知らせるfeedってないかな

Safariがアップデートされない。どうやら、QuickTime(笑)を入れていないと、自動更新されないようだ。

仕方が無いので、手動で更新するしかないが、問題は、Safariはバージョンアップを簡単に知る方法がない。モダンなブラウザは、自動更新に対応しているし、ブラウザから、直接アップデートの有無を調べることも出来る。Safariでは、それができない。

仕方が無いので、Safariのバージョンアップを知らせてくれるフィードがないものか探したが、どうも、これも見つからない。面倒な話だ。

口承文藝史考

柳田國男の、口承文藝史考が面白い。

柳田國男の空想は実に興味深い。

まず、夢について。夢というのは、上代は、個人個人、家々で解釈していたが、次第に文明が進歩していくに連れて、それでは足りなくなった。そこで、夢を語るのがうまい者に、代表して語らせるようにした。これも次第に無力になっていき、ついに、旅の職業の女性に頼るようになったのだとか。

また、その専門家も、無能であった。新しくつくりだすということをほとんどせず、既存の物語を、人の首だけすげ替えて流用していたり、一度大いにウケたネタは、弟子から弟子へと相伝していった。その結果、我々の文学は、ひどく束縛がある。型とかお約束と呼ぶべきものがあって、これから外れると、大衆は見向きもしない。

一つ何かがヒットすると、その後追いが次々と登場するとか、過去のヒット作の続編を延々と作り続ける、現状の娯楽も、なんとかして欲しいものだ。

昔話には、いわゆる正直爺さんといじわる爺さんが登場する。近代風にアレンジされた昔話では、正直爺さんの善行と、いじわる爺さんの悪行とを、ことさらに対比強調することによって、その違いを読者に示してる。ところが、どうもこれは違うらしい。徳分は天意の決するところであるという考え方があって、その命にあらざるものがマネをしても、上手くいかないというのが、本来の意図するところであったらしい。

ソビエトロシアでは、猫がおまえを興ぜしむ!

Home > Similar

Nyzillaが公開された

Winnyサイトブラウザ "Nyzilla" - Download

歓迎すべきソフトウェアである。

WinnyのようなP2Pファイル共有ソフトは、世界中で開発がつづいているが、日本はどうも異質である。ソフトウェアが何をしているか、ユーザーが分からないのである。むしろ逆に、わざと隠そうとしている意図すらある。これはどう考えてもおかしい。ソフトウェアが何をしているかは、ソフトウェアにはわかっているのだから、ユーザーにも知らせるべきである。

いろいろ議論はあったが、結局Winnyに限っては、合法利用が不可能だったと結論しなければならない。中継機能によって、意図しないファイルまで受信、送信してしまう可能性があるのだから。

そういえば昔、Shareのキャシュを一覧表示するソフトウェアのGUI部分を書いたことがある。あれも、本来ユーザーが知っているべき情報が、技術的困難からではなく、意図的に隠されていることへの不満だったのである。結局、Shareはその後、「拡散」と称する、強制アップロード機能が導入されて、合法利用を不可能にしてしまった。残念なことである。

高木浩光@自宅の日記 - Nyzilla 1.0 リリース

「迷惑をかけないようちゃんと使っていただきたい」とのことだが、どうやったら「ちゃんと」、つまり、合法に使えるというのだろう? BitTorrentやLimeWireならば、利用者の意思で合法に使うことができる。しかし、Winnyの場合は、Winnyネットワークに参加している全員が合法に使用しない限り、誰も合法に使うことができない構造に設計されている。

それなのに、「ちゃんと使って頂きたい」というのは、いったいどういう方法なのだろう? 本人に会う機会のある方々は、ぜひ本人からその回答を聞き出してほしい。私も、次の機会ではそうしたい。

47氏も苦しいというか、なんというか。

一時期、P2Pプロトコルは乱立したが、現状では、合法利用ができる現実的なプロトコルとその実装は、BitTorrentプロトコルぐらいなものだろうか。

嗚呼、其真無馬邪、其真不知馬也

ウマくいかないものだなぁ。馬だけに。

世有伯楽、然後有千里馬。 千里馬常有。而伯楽不常有。 故雖有名馬、祇辱於奴隷人之手、 駢死於槽櫪之間、不以千里称也。 馬之千里者、一食或尽粟一石。 食馬者、不知其能千里而食也。 是馬也、雖有千里之能、食不飽、 力不足、才美不外見。 且欲与常馬等、不可得。 安求其能千里也。 策之不以其道。食之不能尽其材。 鳴之而不能通其意。 執策而臨之曰、天下無馬。 嗚呼、其真無馬邪、其真不知馬也。

2009-12-23

canvasならグラデーションがらくちん

ziolog | とある画像の自動生成<ジェネレータ> --解説02--
とある櫻花の画像生成(ジェネレーター) (さくらインターネット創業日記)

このお二方は、グラデーションに一苦労あったようだ。結局、グレイスケールの文字描画と、グラデーションを、別々に作成して合成しているようだ。まったく、ご苦労様というしかない。

canvasならば、そんな余計な苦労をする必要はない。

var context = canvas.getContext("2d") ;
var gradient = context.createLinearGradient(300, 0, 0, 640) ;
gradient.addColorStop(0, "rgb(235, 115, 52)") ;
gradient.addColorStop(1, "rgb(233, 19, 29)") ;
context.fillStyle = gradient ;
// 描画

これで、300x640のcanvasに、右上から左下にかけて、グラデーションで描画される。全体に対するグラデーションなので、一文字ごとにグラデーションがかかるといった、マヌケなことにはならない。

canvasはこのように簡単であり、flashもsilverlightも、サーバーサイドで動的に動画生成してやる必要もなくなる優れものである。

とあるjavascriptの画像生成

とある




方向

色合い
科学色(赤) 魔術色(青)

元ネタ:とある櫻花の画像生成とある画像の自動生成<ジェネレータ>

HTML5のcanvasを使ってやっつけ仕事。グラデーションは面倒なのでやめた。SilverLightやサーバーサイドは、もはや過去の遺物である。これからはクライアントサイドのみで、これぐらいやるのが当たり前になるべきだ。フィード経由で閲覧している人は、ご面倒ではございますが、直接見ていただいくようお願いいたします。

主要ブラウザでテストしてみた結果。
Chrome, Safari: 完璧
Firefox: なぜか@MS ゴシックが意図通りに描画されない。
Opera: canvasの文字列描画をサポートしていない。
IE: えーと……とりあえずお前はカエレ。

グラデーションは、思いのほか簡単だった。

処分に困る自衛隊グッズ

この前、予備自衛官補の訓練に行ってきたら、売店に、「それゆけ! 女性自衛官 プリントクッキー Ver.陸上自衛隊:チーズ味」が売っていたので、買ってきた。

具体的なパッケージは、ググッてもらえばわかるだろうが、現代的な萌え絵のWACが描かれている。

絵師は、「こうたろ」と書いてある。にじいろ桜の中の人である。

面白いから買ってきたのはいいものの、処分に困っている。開けて食べたいと思わないが、さりとて、このまま飾っておくのも無駄である。

誰か欲しい人はいないだろうか。

oldnewthing: デスクトップ上のアイコンは固定できないよ

The Old New Thing : No, you can't lock icons to the user's desktop

I bet somebody got a really nice bonus for that featureに付け加えられるべき、新たなネタを入手した。

わが社の顧客が、あるアイコンを、デスクトップの左上に固定する方法を知りたがっているのですが。

この会社は、他のプログラムがクソに思えるぐらい、究極無敵銀河最強のプログラムを書いているに違いない。まさに驚愕発狂するほどすんばらしいプログラムなので、デスクトップの一番初めに表示して、毎日忘れずに伏し拝むべきなのだ。

まあ、ユーザーは同意しないだろうけどね。

そして、答えはノーだ。あるアイコンを、デスクトップのある位置に強制する、公式の方法はない。

The Old New Thing : I bet somebody got a really nice bonus for that featureも、なかなか面白い。冒頭だけ訳すと、

私には、よくグチる言葉がある。「その機能はオマケがつくほどスバらしいな」と。

「その機能」とは、ユーザーをないがしろにするものである。例えば、ショートカットをクイック起動バーやお気に入りメニューに勝手に入れるだとか、勝手にタスクバーのツールバーを有効にするだとか、なんの意味もなくただ、そこに表示させるためだけに、通知領域にアイコンを追加するだとか、あるいは(私のお気に入りだが)、デスクトップのコンテキストメニューに、初期化に数秒もかかる項目を追加して、ユーザーがビデオカードの設定を変更出来るようにするだとかの類だ。

このビデオカード、ATIとnVidiaのどっちだろう。多分、nVidiaだと思う。

VC10 Beta2 のstatic_assertの規格違反

N3000によれば、static_assertは、以下のように定義されている。

static_assert ( constant-expression , string-literal ) ;

string-literalは、以下のように定義されている。

2.14.5 String literals [lex.string]
string-literal:
    encoding-prefix opt " s-char-sequenceopt "
    encoding-prefix opt R raw-string

encoding-prefix:
    u8
    u
    U
    L

とすれば、以下のコードはコンパイルが通るはずである。

int main()
{
    static_assert( true, "..." ) ;
    static_assert( true, R"***[...]***" ) ;
    static_assert( true, u8"..." ) ;
    static_assert( true, u8R"***[...]***" ) ;
    static_assert( true, u"..." ) ;
    static_assert( true, uR"***[...]***" ) ;
    static_assert( true, U"..." ) ;
    static_assert( true, UR"***[...]***" ) ;
    static_assert( true, L"..." ) ; // これだけは最低でもコンパイル出来るべき
    static_assert( true, LR"***[...]***" ) ;
}

しかるに、VC10 Beta 2では、最初のstatic_assert以外、すべてエラーになってしまう。もちろん、VC10は、raw string literalをサポートしていないし、encoding-prefixも、Lしかサポートしていない。しかし、最低でも、L"..."はコンパイルできてしかるべきだ。それが、何故かできない。

これは明らかに規格違反であるが、実は、ここでエンコーディングプレフィクスが使えても、特に役には立たないのである。というのも、規格では、basic source character set外の文字は、メッセージとして表示することを求められていないからだ。

int main()
{
    // OK. でも日本語が表示されるとは限らない
    static_assert( false, U"でっきるかな? できるかな? さてさてホホゥ!" ) ;
}

規格では、このコードは、コンパイルエラーにならなければならない。その際に、diagnostic messageを表示することが、規格では求められているが、basic source character set外の文字は、表示しなくてもよい。というわけで、このコードは、規格準拠のコンパイラであれば、「動く」が、メッセージとして日本語が表示される保証はないのである。

C++0xで書くネタないかな

最近、C++0xネタを書くと、アクセス数が上がる。これは、C++0xがそろそろ注目され出したということだろうか。この流行にのっかって、ここでなにか書いておけば、ブログの知名度を上げることができるのだろうが、今ひとつネタが思いつかない。

lambdarvalue referenceはすでに解説している。ほかに何か目玉機能はあっただろうか。

templateは、実はあまり変わっていないのだ。conceptさえ否決されていなければ、相当のネタがあったのだが、concept無き今となっては、小粒な改良でしかない。たとえば、一部のテンプレート引数を決め打ち出来る、新しいtypedefとして、テンプレートエイリアスとか、関数テンプレート引数にデフォルトのテンプレート引数を指定出来るとか、便利ではあるが、小さい変更にとどまっている。

C++0xでは、メタプログラミングが一般的になるだろうが、これとて、何も新しい話ではない。C++98以前から、メタプログラミングというのは盛んに行われてきたし、標準ライブラリにも、iterator_traitsというメタ関数が、すでに存在する。ただ、type traits等のライブラリが追加されただけであって、type traitsのほとんどのメタ関数は、C++03の枠内でも、実装可能なのである。

ライブラリが豊富になった。ただ、ライブラリは、ひとつのブログ記事で解説するのに余るほど膨大で、金でももらわなければ到底やりきれない。スレッド、アトミック操作、正規表現、関数ポインタだろうが関数オブジェクトだろうが汎用的にラップ出来るfunction、引数の一部を割り当て出来るbind。時間時刻、乱数、unordered系コンテナ。

2009-12-22

Terry Gilliamへのインタビュー

Terry Gilliam's Three-Reel Circus | Mother Jones

Monty Pythonのアニメーションを作ってた人。

文化の差は未だに理解できない。

上は、完全に同じゲームタイトルである。左が日本版で、右が北米版である。WTF!

なぜメリケンの描くパッケージが、こうならなければならないのか。それにはもちろん、説明可能な理由がある。

まず、すべての人種が等しく出ていなければならないのだ。それゆえ、北米版のパッケージには、黒人とアジア人と白人が、わかりやすく描き分けられている。さらには、腕や脚が、現実的に太くなければならない。

「しかし、これは絵ではないか」という反論は、通じないのである。メリケンは公平さを重んずる国である。公平のためなら、表現の自由が犠牲になっても構わないのである。

2009-12-21

唯有杜康

仕事は依然として見つからぬ。面白いゲームもなし。柳田國男全集は、読んでも読んでもキリがない。現代小説は相変わらずつまらない。新しい風かと思ったラノベは萌え一辺倒でつまらん。結局、読むべき本は古典しかない。人生はクソだ。唯有杜康(ただとこうあるのみ)

ここまで人生がクソだと、酒に逃げたくなる。一体、酒に最適の肴は何か。

それ、肴、あるいはツマミといふものをつらつら考ふるに、生寿司、ニシンの昆布巻き。はて、これらは皆、酢を使用してをる。とすれば、もっとも重要なるものは酢ではあるまいか。ということは、酢をツマミにすれば、万事足る。とはならず。難しいものだ。そもそも、酢そのものがアルコールではないか。いやまて、ひょっとしたら酢で酔ふことが出来るのであるまいか。まあ、酢を飲むぐらいなら、みりんを飲んだ方がいいだらうが。

何が言いたいかというと、生寿司とニシンの昆布巻きほど、素晴らしい酒の肴はないということをいいたいのであって、酢やみりんを飲用するということはどうでもよいのだ。

金之助君のこころに登場するクソ長い手紙

@nifty:デイリーポータルZ:「こころ」の手紙を実際に書いてみる

金之助君の書いた有名な小説、「こころ」は、学校の国語教科書にも載るほど有名だ。その小説の半分以上が、「先生」の書いた「手紙」に費やされている。しかし、これは結構な分量である。いったい、本当に書くとどのくらいになるのだろうか。幸い、それを実行に移した猛者がいた。

まず、筆記にかかる時間である。

40時間近くかかった書き写し

一方、先生はというと、

死のうとしてから十日以上になりますが、その大部分は貴方にこの長い自叙伝の一節を書き残すために使用されたものと思って下さい

十日ぐらいかかったらしい。まあ、死ぬ前の最後の書き収めだと思えば、十日で40時間筆記することは、不可能ではあるまい。

次に紙の量である。作中では、原稿用紙に書いたとあるが、それは手間がかかりすぎるとのことで、ここでは横罫の便箋にしてしまっている。それでも、かなりの量だ。作中では、

その郵便を受け取った私はすぐ不審を起した。それは普通の手紙に比べると余程目方の重いものであった。

重いという表現を使って、手紙の分量を表している。便箋とはいえ、現実にはどのくらいなのか。

それ(便箋)を3冊と4ページで、計154ページ分。

全てを重ねると、厚さ11ミリ・重さ320グラムに。

どうやって送ってきたのかというと、

半紙で包んで、封じ目を丁寧に糊で貼り付けてあった。

封じる便宜のために、四つ折に畳まれてあった。私は癖のついた西洋紙を、逆に折り返して読み易いように平たくした。

現実は、

そうか、より原作に近づけるには、封筒ではなく半紙で包めばいいのだな。そして書いた物は四つ折にすればいいのだな。

とは言うものの、四つ折どころか二つ折りさえ不可能。

折り目をつけるのは不可能だということである。

リンク先では、この偉大なる分量の手紙を受け取った際の反応として、当然起こりうる「私」の反応を考察している。

まず手紙を受け取り、食べ物だと見当をつける。さうして、それが手紙であることに気がついて当惑する。封を開けると、丸めてあった紙が一気にもとに戻ろうとして驚愕する。さうして、その分量に唖然とするのである。さらに流し読みをしてみると、どうやらこれが、遺書らしいことが判明する。「私」は重苦しい雰囲気に押しつぶされてしまふ。

ところで、現代では、紙とペンより便利な文明の利器が存在する。もし、先生がこの手紙を、現代の方法で送ってきたとしたら、その分量はどのくらいだろうか。

とりあえず、青空文庫から、手紙の部分の分量を測ってみた。shift-jisなら169KB、utf-8なら253KB、utf16なら、170KBであった。ためしにutf-8版を、7zipで圧縮してみたところ、66KBであった。

まあ、これぐらいなら、問題なくメールで送れる。そもそもKJV聖書のテキストですら、数MBなのだ。およそ人間の打ったテキストをメールで送る分には問題がない。この程度のサイズなら、メールで受け取っても、別に驚きもないだろう。ただし、受け取った後、それがテキストであることに驚き、さらに読むのにうんざりすることだろう。

追記:青空文庫からコピペした際に含まれていたrubyを削除して、容量を計算し直した。

しかし考えると、別にわざわざ書き写すことはなかったんじゃないかと思う。青空文庫からのテキストで計算すれば、文字数にして、87313文字。400字詰め原稿用紙、219枚分である。改行、空白の行などを考えても、二百数十枚が相場ではなかろうか。

2009-12-20

源氏物語がエロゲ化

夢の浮橋 ~新釈源氏物語~

源氏物語は、森林太郎も言ったように、「眠気を催す書」である。あんまり日本の文化に寄与してはいない。まあ、いわば、腐女子が描いた厨二病ラノベなので、エロゲにするには向いているのかもしれない。

ふと考えてみたが、古典をエロゲにするなら、浄海入道がかなり良い題材だと思う。祇王祇女といい、厳島内侍といい、話題に事欠かない。

それでも、当時の女性の美意識を忠実に再現しようとすると、到底現代人の完成にはあわないだろう。日本の昔のやんごとなき女というのは、薄暗い部屋の中にいて、分厚い着物から、白い顔と手だけだしているものであるというのは、谷崎潤一郎の言だ。

2009-12-19

VS2010のリリースが遅れるらしい

Somasegar's WebLog : Visual Studio 2010 and .NET Framework 4 Beta period extended
Performance problems delay Visual Studio 2010 release | Developer World - InfoWorld

数週間ぐらい。

<functional>をincludeするとインテリセンスが効かなくなるバグは製品版で治っているのだろうか。

冬は鍋

最近、毎日鍋ばかり食べている気がする。無論、鍋は好きだ。鍋に野菜と肉と水をぶち込んで、火にかければできあがる、極めて簡単な料理である。物足りなければ、米やうどんを放りこめばいい。金もかからず、満腹になる、極めて経済的な料理でもある。

では、夏は何を食べていたかというと、野菜炒めだった。フライパンに野菜と肉をぶち込んで、火にかければできあがる、極めて簡単な料理である。あれ、déjà-vuな気がする。

結局のところ、あまり料理のうまくないものが自炊しようとすると、こうなってしまうのだろう。

食事ということを考える。まず第一に、主食がなければならない。主食というのは、炭水化物である。これには、米や小麦、ジャガイモ、トウモロコシなどが一般的である。次に、少しの肉が必要である。また、健康のためには、是非とも野菜をとらねばならない。

簡単な料理で、毎日野菜を摂取するにはどうすればよいか。答えは、野菜炒めか鍋になってしまうのだろう。

文明の進化は既存の物語をつまらなくする。

asahi.com(朝日新聞社):英の小切手、350年の歴史に幕 18年までに廃止方針 - 国際

英国の銀行などが加盟して決済制度を検討する「決済評議会」は16日夕(日本時間17日未明)、小切手を2018年までに廃止する方針を発表した。350年続いた小切手文化に幕が引かれそうだ。

たしかに、今はクレジットカード、インターネット、スマートフォン等の普及によって、小切手よりも便利な決済方法が多数ある。しかし、これは既存の物語を一つ、殺してしまうのではないか。

というは、物語として使い古された、以下のような話だ。

とある筋からの代理人と名乗る男は言った。
「それでは、取引は成立ということでよろしいかな。君はこの件から手を引くのだ。その代わり・・・・・・」
男は懐から小切手帳を取り出すと、署名だけして、私の前に差し出した。
「この小切手に、君の好きなだけの金額を書き込み給え」

この、使い古された手法が、

男は懐から、一枚のカードを取り出すと、私の前に差し出した。
「このカードで、君の好きなだけの金額を使い給え」

男は懐から、携帯電話を取り出した。画面は、どうやら銀行口座の振込のようだ。振込先は、どこで調べたのか、私の口座番号であった。
「ここに、君の好きなだけの金額を打ち込み給え」

となってしまうのか。なんだかひどくつまらない話になりそうだ。

もっとも、今に始まった話ではない。携帯電話の普及によって、連絡を取れないことによる誤解や失敗などの話も、いまや使えなくなってしまった。

寒い

そろそろ、下駄や雪駄で外出するのが辛くなってきた。風流とは寒きものなり。

そもそも、下駄や雪駄で出歩くと、足が汚れる。風流とはむさきものなり。

しかし、足袋を履くのは、身分違いだ。

2009-12-18

いわゆる昔の女ニートの話

いつの事だか定かではないが、少なくとも、今から八百年は昔の話。旅人とその従者達が、宿を求めてさまよっていた。はや、日も暮れぬ、どこか風雨をしのげる宿のあらまほしきをと家々を巡っているうちに、ある大きな屋敷の前にたどり着いた。かつてはさぞかし立派な大福長者の屋敷にてもありなん。今は、門破れ、塀崩れ、荒れ果てたままになっていた。かかるところこそ、泊めてくれるものかもしれぬと、旅人は、門の前に立って、呼ばわった。
「今晩、ここに泊めてもらえぬか」と。

すると、屋敷の内より、ドタドタと足音高く、ひとりの中年女が走り出てきた。いかなる賤女(しずのめ)なれど、まだ多少はマシであろうに、この中年女は、実に醜悪な面をし、ボロボロの衣を着て、しかも、それを恥じることなく、門の前まで、大慌てで走ってきたのである。その醜悪な面に、どこか期待の表情を浮かべながら、
「よき事、よき事。さあさ、やどり給へ、やどり給へ」と、あわてて言った。

やれうれしやと旅人と従者は、あばれ屋敷のひと隅に座をとった。屋は多けれども、人の気配もなし。ただ独りこの中年女のみが住んでいるようである。思えば薄気味悪いところなれども、皆、旅の疲れに、すぐ眠ってしまった。

翌朝、一行は朝食を認め、はや出ていこうとするのを、中年女、またドタドタと品悪く走りでて、
「まてまて、行くな。」という。
「こはいかに」と問えば、
「おれの貸した(こがね)千両、返してから出て行け。さあ、早く返せ、早く返せ」とわめく。

昨日から、この屋敷に薄気味悪さを感じていた従者ども、これにはさすがにこらえきれず、「あらじや、あらじや」といたく嘲り笑った。中年女も負けじと、「返せ、返せ」と、ほとんど狂人の体をなしてわめき返すばかりであった。

この旅人、「しばし」と言いて、荷物の中からなにやら道具を取出して、しばし手の内にて転がして、しばらく考えいるようであったが、ふと顔を上げて、こう言った。

「この親は、もし、易の(うら)という事をしていたのかな」
と問えば、中年女答えて、
「さあ、どうだったろうか。わからんけど、おのれの今やったようなことは、やってた気がする。」
「なるほど。千両の金を貸したから返せというのは、どういうわけかな」

聞かれて、中年女は語りだした。女の親の、まさに死なんとする折、こう言い残したそうだ。「十年後の、今日に、ここに旅人が来てやどを求めるだろう。その人には、わが金を千両貸してある。その旅人に金を返してもらうのだ。いいか、それまでは、この家の物を少しずつ売って、つつましく暮らすのだぞ」と。そこで、この女は、今まで家にある物を、少しずつ売って、今日まで暮らしてきたのであった。それが、今年となっては、とうとう売るべき物もなくなり、どうしようもなくなっているときに、旅人がやってきたのであった。

「その金というのは、あながち間違いでもあるまい。まあ見ていなさい」と、旅人は、従者を部屋から追い出すと、ある柱を叩いた。すると、どうも中が空洞になっているような、響く音がするではないか。
「金はここにある。開けて、少しずつ取り出して、使うのだ」と教えて、旅人は去っていった。

この女の親は、易の占いの上手であった。女のありさまを考えるに、今、女に千両の金を与えれば、久しからずして、すべて使い果たしてしまう事を知り、また、十年後の今日に、易の占いする男が、宿を求めに来ることをも知っていて、かかる事を言い残したのであった。旅人は、親の占い通り、易の心得ある者であったので、金の場所を占い出して、女に教えたのである。

易の占いは、行く末をはっきりを見通すことができるという。

しかしながら、この話を見ても分かるように、未来がわかるからと言って、必ずしも幸福になるとは限らないのである。この醜悪な女は、確かに親の遺産で、一生食うに困らず暮らせたのであるが、果たして幸福だったのだろうか。夫を持たず、何らの事業をもせず、ただ一生を無為のままに過ごしたのである。木の端と変わらぬ暮らしではあるまいか。現代の人は、ニートを現代社会の生み出した問題と捉えがちであるが、まさしく八百年前に、このような話があった以上、そう新しい問題でもないのである。

京の七條渡りで借上していたという肥満女は、このニート女の対極であろうが、それも、あまり感心できぬのである。とかくに人生は難しい。

参考:宇治拾遺物語、八 易の占金取出事

やる気を出すために、なにか文章を書こうと思ったら、こんなものが出来上がった。結局あの話しは、八百年前にも、ニートがいたというお話である。ついでに引き合いに出した、病草紙の肥満女も、あの時代に高利貸しのメタボ女がいたという話であり、なかなか面白い。

Claudia Black

Dragon Age: Origins で、Morriganの声優をしているのは、Claudia Blackである。

BioWareは、正しい声優を選んだと言える。Morriganそのものだ。

2009-12-17

東芝、グローランプの製造を中止す

東芝、グロー方式の点灯管を2010年3月で製造中止 - 家電Watch

電子点灯管があるのに、なんでいまだにグローランプが売られているのか疑問だった。東芝の他にも、グローランプを製造しているところはあるだろうから、まだまだ絶滅しないだろうけれど。

さすがは共産主義の国

中央日報 - 「ネット上のサイト、個人の所有認めず」/中国

今後、中国では個人がインターネットのサイトを所有できなくなる。

ポルノなど社会に有害なコンテンツの流布を防ぐための措置だというのが中国当局の説明だ。しかし一部は、同措置がインターネット上の自由を明白に抑圧するものであり、反政府勢力への監視を強化するのが狙いとして、反発している。

中国インターネット情報センターは14日、個人のインターネットサイト所有を禁じる内容の新しいインターネット政策を発表した。同センターは中国のインターネット上に流通するすべての情報を監視する政府機関だ。匿名を求めた同センターの関係者は「社会に有害な情報を広げるのを防ぐため、今後、個人的目的によるサイトは厳しく禁じる」と説明した。

ブログなど個人が運営するサイトは、以前のインターネットポータルやビジネス向けのサイトでのみ可能だということだ。すでに開設されている個人のサイトは段階的に閉鎖される。14日、アクセスが遮断された「nanjingtaobao.com」というビジネス向けサイトは同日、インターネットを通じて「当局の措置は明白にインターネット上の自由を抑圧するものだ。文革当時の抑圧も同然の今回の措置は即刻取り消されるべき」と強調した。

いたって普通のアカい国の出来事ですな。

2009-12-16

久しぶりにプログラマの求人を眺めてみたら

仕事が全く見つからないので、久しぶりにプログラマの求人を、ネット上で眺めてみたら、だいぶ様変わりしていた。

まず、派遣が壊滅的に減った。去年は猫も杓子も派遣ばかりだったというのに、彼らはいったいどこへ行ってしまったのか。不思議なことだ。

派遣の穴を埋めるかのように、直接雇用の求人が増えているが、いずれも、「実務経験」を求めている。その求人サイトは、とくに転職専用というわけでもないのに、面白いことだ。

C++の求人? そんなものあるわけがない。

浜名湖とダイダラボッチ

柳田國男は、浜名湖に関するダイダラボッチの話を聞き漏らしている。そこで、ここに書いておくことにした。

私は少年時代の大部分を静岡で育った。次のように聞いている。浜名湖は、昔、ダイダラボッチが手をついた跡であると。また、浜名湖の中には、つぶて島という、小さな島がある。これもまた昔、ダイダラボッチがおにぎりを食べていたとき、その中に小石が混じっていた。そこで、プッと吐き出したところ、それが今のつぶて島になったという。

粕汁

自分の場合、やる気が無くなると、体を動かさなくなる。体を動かさなくなると、腹が減らなくなる。つまり、食欲不振となる。

太宰治の人間失格の冒頭とは、つまり、メシを食う程の気力もなくなった状態ではなかろうか。

そうは言っても、数日ろくに食わずにいると、流石に腹が減る。冷蔵庫の中を除くと、白菜とつみれと酒粕がある。そういえば、この白菜とつみれは、数日前に買ってきたのだった。早く食べなければならない。

そんなわけで、粕汁を作った。白菜を全部切り刻んで放り込んだので、具はほとんど白菜になってしまったが、まあ、仕方がない。残しても腐らせるだけだし。

弁慶とダイダラボッチ

弁慶の足跡と称するものは、全国に沢山あるが、どうも、もともとはダイダラボッチの足跡だったらしい。ダイダラボッチの名前が通じない場合、たんに大人(おほひと)と呼んでいたのだが、次第に、あの仁でもよろしということになったらしい。

2009-12-14

日記

やる気がでない。本当にやる気がでない。困ったな。

柳田國男の読書は遅々として進まない。Le Morte d'Arthurも読んでいたが、最初の数章で止まってしまった。漢文も、最近は読んでいない。

ゲームも、最近は面白いものがまったくない。The Elder Scroll 5は、いつになったら出るのだろう。ここ最近、Dragon Age: Originsを始めた。ストーリーは面白いが、戦闘がつまらない。あと、英語がかなり難しい。というのも、固有名詞が極端に多いので、聞いていてもいまいち理解出来ないのだ。その固有名詞の解説は、後でcodexを読まなければならない。ということは、会話を理解するには、二周するしかないのだ。

C++0xも、新しい動きがあるまでは、暇だ。ただ、Boost勉強会を、関西でも開こうという動きがあるらしい。それは興味がある。

だいたい、最も優先すべきことは、仕事を見つけることである。これも、さっぱりやる気がでない。どこかにBoostをバリバリ使うような仕事はないものか。そんな仕事は、あいにくとさっぱり見つからない。結局、私はプログラマとしては向いていないのだろう。

結局、私は身の丈に合わぬ理想を追い求めているような気がする。

2009-12-12

oldnewthing: マヌケは誰だ?

The Old New Thing : Only an idiot would have parameter validation, and only an idiot would not have it

引数チェックの面白いところは、ある者は、マヌケのみが使う機能だと主張し、またある者は、マヌケは利用しない機能だと主張することである。

古き良き時代では、Windowsは、引数チェックなど行っていなかった。もし、ある関数を無効なウインドウハンドルで呼んだならば、アプリはクラッシュする。ある関数を無効なポインタで呼んだならば、アプリはクラッシュする。ある関数を無効なビットマップハンドルで呼んだならば、アプリはクラッシュする。

かつては、よほどたくさんのクラッシュがあったわけだ。

この手のクラッシュは、修復不可能なアプリケーションエラーダイアログとして、表示されることになる。つまり、UAEメッセージとして知られている。

Windows 3.1は引数チェックを、KERNEL, USER, GDIのすべての関数に追加した。もし、アプリが無効なウインドウハンドルを渡した場合、クラッシュする代わりに、エラーが返されるのだ

この変更はあまり喜ばれなかった。「ふーん、あっそう。とうとうやるべきことをやり始めたってわけだな。引数チェックをしないってのは馬鹿げてるしな」

しかし、今日では、引数チェックは、どうもまた道をそれてしまったようだ。無効な引数を検知して、エラーコードを返した場合、それは、単にアプリのバグを先送りにしただけなのだ。むしろクラッシュして、クソみそでウザいエラーメッセージを表示すべきなのだ

つまり、我々は引数チェックを追加する前の時代に戻るべきなのだ。(まあ、クソウザいエラーメッセージはともかくとして)

はたしてマヌケは誰だ?

わざわざ引数をチェックして、エラーを静かに処理して、アプリのバグを先送りにするぐらいなら、クラッシュしてくれた方が、まだマシだったいうお話。

2009-12-11

帰宅

予備自補の訓練より帰宅。

今回はつかれた。久しぶりに酒を呑むことにした。

そして、だいぶ酔った。QueenのDon't Stop Me Nowを延々とリピート再生している。

2009-12-06

またまた

五日間留守にします。

しかし、この一週間は、面白い出来事が多かった。Google日本語入力、Google Public DNS、学研の科学と学習が休刊になったこと、

イフカルト:荒木先生が描いたナルトがとんでもない件
さすがは荒木先生。

@nifty:デイリーポータルZ:メガネが曇らないマスクはこれだ!
参考にしよう。

@nifty:デイリーポータルZ:狛犬をよく見たら子犬がいた
古い狛犬に多いらしい。どんな由来があるのだろう。

あの吉良吉影のネクタイが商品化!JOJO「KILL・A’s tie」:ザイーガ
She's a Killer Queen
Gunpowder, Gelatine
Dynamite with a laser beam
Guaranteed to blow your mind

2009-12-05

年を取ったのか、最近の漫画が理解できない

暇人\(^o^)/速報 : 【画像有】今月のテニスの王子様がとんでもないことになってる件 - livedoor Blog(ブログ)

だめだ、もう理解できない。私は年を取りすぎたものと見える。

まあ、ジャンプといえば、ギャグマンガから始まって、愛と勇気と友情のトーナメント戦へと発展していくのは、王道である。なぜそんな風に進むかというと、結局、人気の出た漫画を、その最初の構想を無視して、なんとか続けさせるためには、トーナメント制の格闘に移行させるのが、ジャンプとしての方法なのだろう。主人公は敵を倒すために成長せねばならず、そうなると必然的に、次の敵はもっともっと強くなければならない。そういうことが繰り返された挙句、どうしようもないほど、インフレが起きてしまうのだろう。

それを防ぎたかったら、一話完結型のギャグマンガにするしかない。

しかし、大衆というのはこんな漫画を求めているのだろうか。短く簡潔に数巻で終わって、なお面白い漫画というのは、当然あるはずだ。それを、このようにだらだらと引き伸ばして連載を続けても、面白いわけがないと思うのだが、大衆はむしろ、引き伸ばしを好むのか。

この手の引き伸ばしは、漫画に限った話ではない。最近私は、小説を読むことができなくなった。とくに、長い小説を読むことができないのだ。別に、長文が読めなくなったというわけではない。読解力は、むしろ年々上がっていると思うのだが、長文小説は読めない。というのも、長文小説の中盤になると、明らかに、作者が字数を埋めるだけの意図を以て、文章を書いているということが、あからさまに分かってしまう。はたして、文章に長さは必要であろうか。言いたいことができるだけ短い文で表現できれば、それで十分ではあるまいか。

そんなわけで、私は今、現代小説を全く読んでいない。

あるいは、私は年を取りすぎて、長い話が楽しめなくなったのだろうか。

洗車失敗

かつてSnoop Dogg云へり、「宜しく汝のホースを抑ふるべし」と(HorseとHoseをかけている)

2009-12-04

いかにしてWebデザインがクソみそになってゆくか

How a Web Design Goes Straight to Hell - The Oatmeal

顧客「俺は社長だからもっと口を出すぜ。俺が仕事したっていう自己満足が欲しいんだよ。分かんだろ? なあ? 『ユーザーエクスペリエンス』とか『コンバーション志向』って用語もカッコいいからじゃんじゃん使うぜ。あと、俺はコンピューターの使い方なんてしらねーんだよ。悪いかタコ」

顧客「もうちっとデザインをポップにしてくれんかね。あとエッジーにしてほしいもんだな。なんかこのままじゃイメージと違うんだよなー分かんだろ? なあ?」

顧客「直角が多くて困るんだよなあ」

顧客「俺のカーチャンの意見も取り入れようと思うんだ。1982年当時は現役だったんだぜ。だからデザインには目があるってもんだ」
顧客の母「ねこよ。ねこを入れるべきよ。だってみんなネコは好きでしょ?」

顧客「俺の飼ってる犬ミッフィルは家族も同然だ。うちのわんこが語りかけているようなデザインにしたいもんだな」

顧客、WebサイトのスクリーンショットをPhotoshopで修正して、送りつける。

時代の変化を拒絶する人々

どうやら、Google日本語入力の予測変換を気に入らぬ人がいるようだ。曰く、「予測変換は偏っている」、「予測変換に我々の日本語が支配せられてしまう」、云々。

一昔前の、「ワープロでは正しい日本語が書けない。宜しくペンを使うべし」という議論を彷彿とさせる。この議論は、今や、「どうでもいいじゃないか」の一言で、片付けられてしまう。

実際、どうでもいいのである。時代というのは常に、「甲なのか乙なのか」と争っているうちに、「実はイロハなんだ、ABCDなんだ」といわれて、甲乙などどうでも良くなってしまうのである。

ただし、あえてこの議論に乗っかるとすれば、予測変換の利点と、彼ら時代遅れの老害の非を、上げることはできる。

彼らはいう。「予測変換は我々の日本語を制限する。例えば、だ・である調で書きたいとしても、変換候補がです・ます調であれば、面倒なのでそちらを使ってしまうだろう」と。またいう、「予測変換は、時として不思議な変換を行うので、到底仕事で使うことはできぬ」と。

ひとつめの非難に対しては、ソフトウェアが学習機能というものを設けて、ユーザーの癖を学習すればいいだけの話である。ふたつめは、そもそも従来のかな漢字変換ですら、誤変換が多いのである。してみれば、彼らは従来のIMEをも、仕事で使うことはできぬであろう。

プライバシーの問題も叫ばれている。がこれは、別にGoogleに限った話ではないだろう。

ベジタリアンも喰える肉、開発さる

Meat grown in laboratory in world first - Telegraph

とうとう人工肉が開発された。

やっていることは、生きている豚の筋組織を採取し、培養するだけである。

つまり、ベジタリアン(笑)も安心して食べられる肉だということだ。なぜなら、彼らの肉を喰わない理由というのは、主に、「動物様を屠殺するなんて許せん」、ということなのだから。その割には、彼らは植物様を殺して食べたり、植物様の命を弄ぶ品種改良された野菜を食べることには、躊躇しないようである。この矛盾を、彼らはどのように解決しているのか、それは私の知るところではない。

2009-12-03

Mark Russinovich、MinWinについて語る

Mark Russinovich on MinWin, the new core of Windows | Software News - Betanews

Google日本語入力の面白予測変換集

Google日本語入力の、面白予測変換の例をいくつか見つけたので、ここにメモしておく。

ただしま
ただし魔法は尻から出る
ただしい
ただしイケメンに限る
ひとがご
人がゴミのようだ
なにをする
何をするだァーッ
たいほ
逮捕しちゃうぞ
しんせいき
新世紀GPXサイバーフォーミュラ
こちらか
こちら葛飾区亀有公園前派出所
こいするお
恋する乙女と守護の楯
おさななじみ
幼なじみはベッドヤクザ
れれれ
レレレのおじさん
まほうじ
魔法陣グルグル
じょじょの
ジョジョの奇妙な冒険
やまだお
山田オルタナティブ
くそみ
くそみそテクニック
みこみこ
巫女みこナース
ぎおんし
祇園精舎の鐘の声
きみが
君が主で執事が俺で
まぶら
マブラヴオルタネイティブ
きみがの
君が望む永遠
きしんほ
機神咆吼デモンベイン
みらいへ
未来への遺産、未来への咆哮
とばくも
賭博黙示録カイジ
とばくは
賭博破戒録カイジ
らきすた
らき☆すた
きどう
機動戦士ガンダム
きどうぶ
機動武闘伝Gガンダム
はたらい
働いたら負けかなと思ってる
まほうしょ
魔法少女リリカルなのは
ちょうじく
超時空要塞マクロス、超時空世紀オーガス、超時空騎団サザンクロス
こうかくき
攻殻機動隊
よーし
よーしパパ特盛頼んじゃうぞー
あたらな
当たらなければどうということはない
ぼうや
坊やだからさ
おやじに
親父にもぶたれたことないのに
せいきま
聖飢魔、世紀末リーダー伝たけし、世紀末の魔術師、世紀末の詩、世紀末覇者
わたしが
私がクマにキレた理由
ざんぎゅ
ザンギュラのスーパーウリアッ上
いんどじ
インド人を右に
じゅげむ
じゅげむじゅげむナンタラカンタラ
ふとんが
布団が吹っ飛んだ
あつは
アツはナツいね
あるみかん
アルミ缶の上にあるミカン
それはわたしの
それは私のおいなりさんだ

どうも、主にエロゲのタイトルが、面白い予測変換を引き起こす原因となっているようだ。

ところで、たまに変換がおかしい場合がある。例えば、「お茶を淹れる」が変換できない。そもそも、「淹れる」という単語が存在しない。そういう場合は、以下から報告することができる。
誤変換報告フォーム - Google 日本語入力 ヘルプ

Google日本語入力がすごすぎる

Google 日本語入力 - ダウンロード

Google日本語入力は、Yet Another Japanese IMEである。これはすごい。何がすごいかと入って、辞書だ。漫画やアニメの単語は、ほぼ一発で変換してくれるし、ネットスラングの類も、一発変換できる。さらに、サジェスト機能も優秀だ。

空条承太郎
空条徐倫
荒木飛呂彦
覇王翔吼拳を使わざるを得ない
滅殺豪波動
瞬獄殺、春獄殺
狼牙風風拳
界王拳
魔貫光殺砲
波紋疾走
二重の極み
北斗百裂拳
二指真空把
岩山両斬波
華山群狼拳
邪気眼
エターナルフォースブリザード
パッド長
幻想郷、紅魔郷、妖々夢、萃夢想、永夜抄、花映塚、風神録、緋想天、地霊殿、星蓮船
博麗霊夢、霧雨魔理沙、射命丸文、河城にとり

驚くべし。これらは皆、一発で変換できる。

2009-12-02

うげ、これはまずい

template<class InputIterator, class OutputIterator> OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result);

Requires: result shall not be in the range [first,last).

template<class InputIterator, class OutputIterator> OutputIterator move(InputIterator first, InputIterator last, OutputIterator result);

Requires: result shall not be in the range [first,last).

うわ、やっべ。俺の書いた既存のコード間違えまくりんぐ。

というのも、VC++のmoveやcopyは、メタプログラミングによって、使える場合はmemmove()を使っているので、コンパイルが通り、普通に動くのだ。

シンタックスシュガーとしてのlambdaの解説

本の虫: lambda 完全解説で、lambdaの全機能は、ほぼ網羅したと思う。lambdaの文法は、それほど難しくはないと思うのだが、難しいと感じる人がいるらしい。とくに、キャプチャが理解できない人がいるそうだ。そこで今回は、lambdaの根本を解説してみようと思う。

lambdaというのは、そもそも関数オブジェクトのシンタックスシュガーなのである。例えば、

namespace hito {

template< class InputIterator, class Function >
Function for_each(
    InputIterator first,
    InputIterator last,
    Function f )
{
    for ( ; first != last ; ++first )
        f( *first ) ;

    return f ;
}

}


int main()
{
    std::vector<int> v ;

    for ( int i = 0 ; i != 10 ; ++i )
        v.push_back(i) ;

    hito::for_each(v.begin(), v.end(),
        [](int x){ std::cout << x << std::endl ; }
    ) ;
}

このコードは、これ以上ないくらいに分かりやすいC++のコードである。今、for_eachのしていることを分かりやすくするため、自前で実装してみた。for_eachは、イテレーターに対して、引数として與えられた関数オブジェクトを呼び出すのである。関数オブジェクトは、この場合、lambdaである。

とはいえ、lambdaを理解できない人間は、このコードもまた、理解できないのである。では、以下のように書き換えてはどうか。

struct lambda
{
    void operator ()( int value ) const
    {
        std::cout << value << std::endl ;
    }
} ;


int main()
{
    std::vector<int> v ;

    for ( int i = 0 ; i != 10 ; ++i )
        v.push_back(i) ;

    std::for_each(v.begin(), v.end(),
        lambda()
    ) ;
}

このように関数オブジェクトを渡しているに過ぎないのである。lambdaは所詮、関数オブジェクトのシンタックスシュガーであることが、実感できたことと思う。

しかし、変数のキャプチャはどうか。例えば以下のコード。

int main()
{
    std::vector<int> v ;

    for ( int i = 0 ; i != 10 ; ++i )
        v.push_back(i) ;

    int sum = 0 ;

    std::for_each(v.begin(), v.end(),
        [&]( int value ){ sum += value ; }
    ) ;

    std::cout << sum << std::endl ;
}

これは実に不可思議である。lambdaが関数オブジェクトであるのはまだしも理解もできようが、なぜ、その関数オブジェクトであるlambdaが、定義された場所の関数の変数を、自分でも使えるのか、理解に苦しむ。こんな奇妙なことが、単なる既存の関数オブジェクトのシンタックスシュガーであるわけがない――と思うかも知れない。

しかし、依然としてlambdaは、関数オブジェクトのシンタックスシュガーなのである。

class lambda
{
private:
    int & sum ;

public :
    lambda(int & ref) : sum( ref )
    { }
    
    void operator ()( int value ) const
    {
        sum += value ;
    }
} ;


int main()
{
    std::vector v ;

    for ( int i = 0 ; i != 10 ; ++i )
        v.push_back(i) ;

    int sum = 0 ;

    std::for_each(v.begin(), v.end(),
        lambda( sum )
    ) ;

    std::cout << sum << std::endl ;
}

ご覧のように、lambda関数オブジェクトは、コンストラクタの引数で、その関数内の変数を参照に取るだけである。lambdaのキャプチャとは、根本的には、この程度のものなのである。

C++0x以前では、関数オブジェクトは、お世辞にも、活用されているとは言い難かった。既存の関数ポインタより圧倒的に便利なのだが、如何せん、その文法が汚い。上記のlambda関数はいずれも、たった一行の、短いコードである。本質的には一行のコードを書くために、関数オブジェクトは、あまりにも文法上必要なゴミが多い。そのため、使用を敬遠されていたのだ。lambdaなら、その場所に、直に書くことが出来る。

lisp、python、javascript、ruby、C#等の言語を話す人からみたら、C++のlambdaは、制限が多いように思われるかも知れない。しかし、強い静的な言語であるC++としては、仕方がないのである。

2009-12-01

oldnewthing: WIN32_LEAN_AND_MEANの由来

The Old New Thing : Where did WIN32_LEAN_AND_MEAN come from?

asdfはWIN32_LEAN_AND_MEANの由来が疑問であるようだ。

WIN32_LEAN_AND_MEANシンボルは、Windows 95時代に、windows.hをincludeした際、多くのヘッダファイルを省略する目的で導入された。windows.hを覗けば、どのファイルが省略されるのかが分かる。

このシンボルは16-bit Windowsから32-bit Windowsへの移行の一環として、追加されたものである。16bitのwindows.hは、多くのヘッダファイルをincludeしておらず、WIN32_LEAN_AND_MEANを定義することによって、16bit Windowsの、Windows プログラムを書くに当たって最小限のヘッダという思想を、取り戻すことができるようにするものであった。これは、ヘッダファイルを細かく自分で管理したいプログラマに歓迎されたし、また、利点もあった。というのも、このシンボルが作られた当時は、プリコンパイルドヘッダーファイルは、一般的ではなかった。私の記憶する限りでは、50MHzの80486に8MBのメモリでは、WIN32_LEAN_AND_MEANを使うことによって、Cファイル一個あたり、三秒のコンパイル時間の短縮に繋がったのである。あるプロジェクトで20個のCファイルを使っていたならば、実に一分間もの時間の節約になる。

ムーアの法則とプリコンパイルドヘッダーとが、WIN32_LEAN_AND_MEANを、ほとんど無用にしてしまった。もはや、時間の短縮にはならぬ。しかしある時代では、確かに役立っていたのだ。

帰宅

予備自補の訓練より帰宅。

予備自補の訓練で、前々から思っていることをひとつ。

予備自補の訓練は、五日間単位で行われる。駐屯地の中は、かなりの異世界である。どのように異なっているかを文章で表現するには、遺憾ながら私の筆の及ぶ所ではない。ただし、強いて拙筆を用いれば、駐屯地の中は、外との接点があまりないと、隔絶された別世界である。加ふるに規則正しい生活を以てす。

つまり、訓練は非日常であり、精神的に疲れるのである。精神が疲労すると、自ずと挙動に表れてくる。では、予備自補の訓練においては、どのような挙動に表れるのか。下ネタである。

人の精神というのは、以外と脆いものである。

ちなみに、すでに達観した感のある私としては、「枯楊春老更生稊(こやうはるおいてさらにていをしょうず)」といった具合なのだ。もうトシだろうか。そういう話にはついて行けない。

2009-11-26

また訓練

予備自補の訓練で、また五日間留守にする。帰ったら仕事を探さなければ。

lambdaに関する記事がやたらと人気だ。意外とlambdaの需要はあるのかもしれない。たしかに、rvalue referenceより、lambdaの方が、一般に使われると思う。そもそもlambdaは、既存の関数オブジェクトを、より気軽に使うことを目的としているのだから。

insertion sortをジェネリックに実装してみた

namespace hito {

namespace detail {

template < typename Iterator >
void rotate( Iterator first, Iterator last )
{
    using namespace std ;

    for ( Iterator i = first ; i != last ; ++i )
    {
        swap( *first, *i ) ;
    }
}

}

template < typename Iterator, typename Compare >
void insertion_sort(
    Iterator first,
    Iterator last,
    Compare comp  )
{
    typedef typename std::iterator_traits<Iterator>::value_type value_type ;

    Iterator i = first ;
    for ( ++i ; i != last ; ++i )
    {
        Iterator iter =
            std::find_if( first, i,
                [&](value_type const & value){ return comp( *i, value ) ; }
            ) ;

        if ( iter != i )
        {
            Iterator last = i ;
            ++last ;
            detail::rotate( iter, last ) ;
        }
    }
}

}

やりすぎたかもしれない。

調べたら、広く知られているinsertion sortのコードは駄目すぎる - やねうらお-よっちゃんイカを食べながら年収1億円稼げる(かも知れない)仕事術よりちょっぴり遅かった。

ただ、insertion sortは、ほとんどソートされた配列に提供するのが筋である。だから、逆から追っていくのが普通の実装だ。bidirectionalにしていいなら、もうすこし早くなるのかも。

追記:std::move()のイテレーターは、オーバーラップできないので、自前で書いた。

2009-11-25

rvalue reference 補足

前回、rvalue reference 完全解説なる記事を書いた所、ある程度の反響を得た。このような個人のブログでは、数人が思う所を書けば、まあ、ある程度の反響と言って差し支えないのである。

しかるに、皆rvalue referenceの理解に苦しんでいる様子だ。果たしてあの解説が至らなかったのであろうか。しかし、あの解説は、これ以上ないくらい簡単に書いたはずである。

実際、value referenceは、名前の通りのrvalueへのreferenceに過ぎぬのだし、std::move()とstd::forward()は、キャストに過ぎぬのだ。std::move()は、rvalueへのキャストであり。std::forward()は、lvalueをlvalueへ、rvalueをrvalueへキャストするのである。それだけのことなのである。

しかし、現実に理解に苦しんでいる者がいる。これは一体どういう事なのか。つくづくこの事を案ずるに、これは畢竟、rvalue referenceが理解できないのではなく、C++のその他の規格を理解していないのではないかと思う。

lvalueとrvalue

どうやら、lvalueとrvalueの違いを理解していないC++プログラマがいるらしい。C++98の頃から、lvalueとrvalueはある。これを理解せずには、C++98すら使いこなせないのではないかと思うのだが、不思議なものだ。

思うに、lvalueとrvalueというのは、名前がよろしくない。もはや、left, rightとは何の関係もないのだ。従って、もしC++の本で、左辺値、右辺値、などという訳語を使っている本があれば、例外なくクソであることが予想されるので買わない方が良い。

named valueとunnamed valueの方が分かりやすいという意見もある。確かに、rvalueに名前はない。また、rvalueは一時的なオブジェクトである。

templateのargument deduction

ある者は、std::forward()を、テンプレートではない普通の関数の中もで使うべきかどうか疑問に思っている。本来、こんな疑問が生ずること自体おかしいのだ。std::forward()はargument deductionに関係する問題なのだから。

そしてふと思ったのだが、もしや、世の中にはargument deductionを知らないC++プログラマがいるのではあるまいかということだ。一体どうやってテンプレート関数を書いているのか知らないが、どうやらいるらしい。不思議なことだ。

argument deductionとは、テンプレート引数を関数の引数として使った場合、テンプレート引数を指定しなくても、型を推定してくれる機能のことだ。

template < typename T > void f ( T ) {}
template < typename T > void g ( T * ) {}
template < typename T > void h ( T const * ) {}


int main()
{
    int const * ptr = nullptr ;

    f( ptr ) ; // T は int const *
    g( ptr ) ; // T は int const
    h( ptr ) ; // T は int
}

もしこの機能がないならば、プログラマは非常なる不便を被るであろう。

そのargument deductionとして、rvalue referenceがlvalueになるのである。

template < typename T > void f ( T && )
{
    std::cout<< std::is_lvalue_reference<T>::value << std::endl ;
}

int main()
{
    int x = 0 ;

    // T は int &
    f( x ) ;

    // T は int
    f( std::move(x) ) ;
}

つまり、テンプレート引数で、関数の引数をrvalue referenceにすると、引数がlvalueかrvalueか、インスタンス化されるまで分からないのである。

だから、std::moveは使えないのである。うっかり引数のlvalue referenceをrvalue referenceにしてしまおうものなら、呼び出し元が悲惨なことになるだろう。したがって、lvalueはlvalueのままにしておいてくれる、特別なキャストが必要なのである。

java 7が斜め上を行っている件について

Javaがクソなのは今に始まった話ではないのだが、Java 7でさらにクソミソになるようだ。

New language features in Java 7 « JoeJag :: Tech

Java 7にはDiamond Operatorなるものがある。

アイディアとしてはこうだ。いままでは、こんな風に書かなければならなかった。

Map<String, List<String>> anagrams = new HashMap<String, List<String>>();

これは、どう見ても冗長で無駄だ。モダンな言語をみるに、C++0xのautoといい、C#のvarといい、これらの冗長なコードを回避できる方法を提供している。時代遅れで池沼のJavaも、なんとかC++やC#のマネごとをしたかったものとみえる。連中の解決方法は以下の通り。

Map<String, List<String>> anagrams = new HashMap<>();

わー、ボク、よくできまちたねー。ナデナデ。

連中は何考えているんだろう。C++もC#も、型を右側に記述し、代入する変数に、わざわざ型を記述しなくてもすむようにしているのだ。なぜなら、式の結果の型を、コンパイラは決定できるからなのだ。しかし、Java 7は、依然として変数の型を指定しなければならないことに変わりない。何も変わっていないのである。

海外は進んでいるなぁ

Apple "refuses to repair smokers' Macs" | News | PC Pro

それに引き替え、このクソな日本は。亡命したいくらいだ。さっさとタバコを禁止にしろ。

2009-11-24

C++0xの新しい乱数ライブラリ、random

注意:最新ドラフトのN3000のrandomの規定は、コンセプトが却下される前の文面であり、今後、変更があると思われる。

C++は標準ライブラリが貧弱であるとは、よく言われることだ。ことに、乱数に関しては、貧弱の極みである。ご存じのように、C++は、Cから標準ライブラリを引き継いでいる。rand()だ。これは、0からRAND_MAXまでの値を返すと規定されている。RAND_MAXは実装によって異なるが、ほとんどの処理系では、32767である。現代の乱数需要を満たすには、あまりにも小さすぎる。

この状況を打破すべく、C++0xには新しい乱数のライブラリが盛り込まれた。randomである。これはBoostの実装を元にしているのだが、Boostとは少し違っている。今回はそのrandomを、浅く触りだけ紹介しようと思う。というのも、ライブラリの細かなメンバ関数の一つ一つまで説明するのは、甚だ冗長であるし、残念ながら私は、乱数のアルゴリズムを詳細に論ずるだけの数学的知識を持ち合わせていないからだ。そんな私が解説するのであるから、数式を見ただけでジンマシンがでるほどの数学アレルギーをお持ちの型も、安心して読み進めてもらいたい。

使い方

randomは、<random>をincludeすることによって使用できる。

#include <random>

randomを利用するに当たって、最低限知っておかなければならないことは二つある。engineとdistributionである。

engine

エンジンは、乱数生成のクラスである。乱数はこのクラスで生成されることになる。標準で、様々なアルゴリズムが用意されている。もちろん、標準のコンセプトに乗っ取って、自分で実装することも出来る。コンセプトはすでに廃止されたが、便宜上こう呼ぶことにする。あるいは、インターフェースとでもいうべきか。

標準ライブラリは、おもに三つのエンジンを提供し、そのエンジンをベースに、さらに三つのアダプタエンジンを提供している。

とはいっても、一般ユーザーが主に使うのは、そのエンジンをさらにtypedefしたものである。ここでは、主にメルセンヌ・ツイスタを使うことにする。その他のアルゴリズムや、具体的な実装方法に興味があれば、規格を読んでもらいたい。

さて、早くコードが読みたいせっかちな諸君のために、エンジンを使ったコード例を示そう。

int main()
{
    std::mt19937 engine ;

    std::cout << "min: " << engine.min() << std::endl ;
    std::cout << "max: " << engine.max() << std::endl ;

    for ( int i = 0 ; i != 10 ; ++i )
        std::cout << engine() << std::endl ;
}

これで乱数は生成できた。めでたしめでたし・・・・・・ならず。

残念ながら、話はハッピーエンドには終わらないのである。確かに乱数は生成できた。ただし、これではあまり使い勝手がよくない。無論、諸君は私より数学が得意であろうから、「値の範囲が便利じゃないって? 別にかまわんよ。値の範囲の調整ぐらい自前でやるさ」と思うかも知れない。しかし、私は先ほども言ったように、数学的知識が絶望的に足りないので、一体どうやって正しく値の範囲を変更すればよいのか分からない。私は先天的に数学を理解する脳の部分を持たずに生まれてきているので、数式というものは、まったく頭に入らないのである。

そもそも、仮に値の範囲を変更する方法を知っていたとしても、いちいちそんな面倒な事を自前で書きたくはない。真に優れたプログラマというのは、自分でコードを書かないものである。コードを書かなければ、バグを生み出す恐れはないからだ。幸い、標準ライブラリは、値を希望の範囲に変えてくれるクラスを提供してくれている。

distribution

engineクラスの生成する乱数を、ユーザーの欲しい値の範囲に変えてくれるのが、distributionクラスの役割だ。

ここで、六面のサイコロを作るものとする。六面のサイコロは、1から6までの数字を、一様に、ランダムで出すものである。型は、intでいいだろう。さっそく、distributionクラスを使って、サイコロを実装しよう。

int main()
{
    std::mt19937 engine ;

    std::uniform_int_distribution<int> distribution( 1, 6 ) ;

    for ( int i = 0 ; i != 10 ; ++i )
        std::cout << distribution(engine) << std::endl ;
}

このように、uniform_int_distributionを使うことによって、整数型の、範囲を指定した乱数を生成させることが出来る。ここではintを使ったが、shortでもlongでも、signedでもunsignedでも、整数型なら、自由に使える。

実数の乱数

整数だけではなく、実数の乱数も欲しい所である。実数の為には、uniform_real_distributionクラスが用意されている。

いま、0.0から1.0の範囲の実数を、一様かつランダムに生成したいとする。一体何故、このような乱数が必要になるのか、私にはいまいち分からないが、諸君の大部分は、私より数学が得意であろうから、なにがしかの理由を知っているのであろう。

int main()
{
    std::mt19937 engine ;

    std::uniform_real_distribution<double> distribution( 0.0, 1.0 ) ;

    for ( int i = 0 ; i != 10 ; ++i )
        std::cout << distribution(engine) << std::endl ;
}

ご覧の通りである。

distributionは他にもある。ここで紹介していないのは、uniformではない乱数を返すものである。つまり、範囲内の値が、同じ確率ででないのである。こう書くと、奇妙に聞こえるかも知れない。例えば、Normal Distributionだ。数学の分からない私には何がそんなに嬉しいのか理解できないが、範囲内の値を、正規分布な乱数で返すdistributionクラスである。その他にも、BernoulliだのPoissonだのSamplingだのと、色々あり、しかもその中d、さらに細かく別れているのだが、私にはさっぱり理解できない。多分、数学の出来る変態達には、垂涎もののクラスなのだろう。

seed

なるほど、randomの使い方はだいたい分かった。しかし、このままでは、実際に使うことは出来ぬ。凡そ乱数というものは、初期化を必要とする。メルセンヌなんとかいうアルゴリズムが、エラい数学のセンセーのお墨付きであったとしても、所詮は数式に過ぎぬ。何か外部から、最初の値を、真の乱数を与えてやらなければならないのだ。さもなくば、乱数の値は、プログラムを何度実行しても、同じものになってしまう。

標準ライブラリには、seed_seqというクラスがあり、これでもって、エンジンを初期化できる。

追記:engineに渡すseed sequenceを満たしたクラスのオブジェクトは、lvalueでなければならない。

    std::vector< std::uint_least32_t > v ;
    std::seed_seq seed( v.begin(), v.end() ) ;
    std::mt19937 engine( seed ) ;

seed_seqは、イテレーターをとる。各value_typeは、2の32乗に丸められて、seed_seqのprivateなメンバ変数であるvectorに格納される。エンジンは、seed_seqを使って初期化される。要素はいくつあってもかまわない。ただし、すべて使われるという保証はない。それは実装依存である。

問題なのは、一体どうやってこのvを乱数で埋めるかという話である。

真の乱数

乱数には、疑似乱数と真の乱数がある。今まで使っていたのは、疑似乱数である。ここでは、真の乱数が必要なのである。

本当の意味での真の乱数というのは、ラジウムとガイガーカウンターを組み合わせたデバイスであろう。なぜなら、ラジウムがいつアルファ崩壊するかは、観測するまで分からず、完全に確立の問題だからである。

余談だが、私は常々これに疑問を持っている。我々が観測しようがしまいが、アルファ崩壊する時は決まっているはずである。むしろ、アルファ崩壊を観測した我々と、アルファ崩壊を観測していない我々の、両方が存在するのではないかと思う。それはさておき。

残念ながら、そのようなデバイスは非常に高価であり、一般ユーザーのコンピューターには取り付けられていない。そこまで真の乱数とはいかなくても、ある程度のまともな乱数は、一般のコンピューターにも存在する。たとえば、現在の時刻であるとか、CPUの温度などだ。

幸いにして、C++0xの標準ライブラリには、そのような乱数を生成するクラスがある。random_deviceである。

int main()
{
    std::random_device rnd ;
    for ( int i = 0 ; i != 10 ; ++i )
        std::cout << rnd() << std::endl ;
}

「なんだ。最初からこれを使えばいいではないか」と思うかも知れない。ところが、普通の乱数の需要は、ここまで大がかりな乱数を使う必要はないのである。その理由については、私より簡潔かつ詳しく解説している本が山ほどあるので、ここでは説明しない。もし、分かりやすい本を知らないのと言うのであれば、結城浩の『新版暗号技術入門――秘密の国のアリス』がおすすめである。今手元にないので確認できないが、確か乱数について解説していたと思う。

さて、では早速、エンジンを初期化しよう。

int main()
{
    // ランダムデバイス
    std::random_device rnd ;

    // 初期化用ベクタ
    std::vector< std::uint_least32_t> v(10) ;

    // ベクタの初期化
    std::generate( v.begin(), v.end(), std::ref(rnd) ) ;
    
    // 乱数エンジン
    std::mt19937 engine( std::seed_seq( v.begin(), v.end() ) ) ;

    // distribution
    std::uniform_real_distribution<double> distribution(0.0, 1.0) ;
    

    for ( int i = 0 ; i != 10 ; ++i )
        std::cout << distribution(engine) << std::endl ;
}

美しい。

random_deviceをstd::ref()で渡しているのには、理由がある。というのも、このクラス、コピーもmoveもできないのである。したがって、関数オブジェクトとして渡そうと思ったら、参照で渡さなければならない。これも、C++0xには、便利な関数が<functional>にあるので、問題ない。

Boost.Randomとの違い

BoostにはRandomというライブラリがあり、TR1はこれを参考にして設計された。とはいえ、実際のC++0xに採用されたrandomは、Boostのものとは、多少異なっている。特にBoostユーザーは、variate_generatorがないことに驚くであろう。しかし、これには理由がある。

variate_generatorは、engineとdistributionをラップする便利なクラスである。なぜ、C++0xにはないのだろうか。

いくつかの乱数のアルゴリズムでは、variate_generatorを使えば、ある種の最適化ができるはずだった。これは、variate_generatorの本来の目的だ。ところが、実際に実装してみた所、別にvariate_generatorがなくても、問題がないことが分かった。さらに、variate_generatorが、乱数のアルゴリズムの実装を制限する可能性も指摘された。そんなわけで、variate_generatorの本来の目的は、消えてしまったのだ。そこで、variate_generatorは、規格から消されることになった。

しかし、engineとdistributionのラッパーとしての役割はどうすればいいのか。二つの変数を管理するのは面倒だ。一つにまとめたい。わざわざ自前でクラスを書かなければならないのだろうか。

実は、C++0xの力を以てすれば、そんなことはわけないのである。

int main()
{
    // bindを使う方法
    auto rnd1 = std::bind( std::uniform_real_distribution<double>(0.0, 1.0), std::mt19937() ) ;
 

    std::cout << rnd1() << std::endl ;

    // lambdaを使う方法
    std::mt19937 engine ;
    std::uniform_real_distribution<double> distribution(0.0, 1.0) ;

    auto rnd2 = [&]{ return distribution(engine) ; } ;

    std::cout << rnd2() << std::endl ; 
}

もちろん、autoの代わりに、std::functionを使ってもよい。

最後に

このように、C++0xのrandomは、数学がまったく理解できないものでも使いこなせる、実に便利なライブラリなのである。

oldnewthing: ウィリアムって人と替わってもらえる? さっき分かりやすかったからさ

The Old New Thing : Can I talk to that William fellow? He was so helpful

えー、本日はタイムマシンを使って、少し昔へ行ってみようと思います。ガイドはこの人、セス・マンヘイム君。当時その現場に居合わせておりました。

タイムマシンの日付を1989年、11月22日に合わせます。今からちょうど、20年と一日前の出来事でございます。あちらに見えますように、今、ビル・ゲイツが、新しいオフィスビルの製品サポート部門を視察しております。視察中、彼が今、一人の社員が電話と取るのを遮って、言いますことには、「私が替わりにやってもかまわないかね?」と。

ビルはヘッドセットを装着し、席に着き、電話を取りました。「はい、こちらはマイクロソフトの製品サポート、担当はウィリアムです。どういたしましたか」

ビルはお客様と話を致しまして、問題を把握しまして、製品サポートKBを検索しまして、検索結果からさらに探しまして、解決方法を見つけまして、お客様が問題を解決できるよう、辛抱強く説明しております。

お客様は、ウィリアムが問題を素早く解決し、また対応態度も真摯であったことに、大変満足されたようでございます。ビルは、「マイクロソフトの製品をご利用いただきありがとうございました」と言って、電話を終えたのでございます。

ビルは終始、自分のことをウィリアムと称しておりました。お客様は、外ならぬ、あのビル・ゲイツが対応致したとは、夢にも思わなかったことでございましょう。

さて、このお話は、まだまだ続くのでございます。

この時の時刻はちょうどお昼時にあたり、サポート社員のほとんどは昼食に席を外しておりましたが、この話はすぐに広まりました。そして、ビルが製品サポートの電話を取ったということは、すぐにその部署全体の知る所となったのでございます。

その後しばらくして、同じお客様が、さらに質問の電話をかけてこられました。

「もしもし、さっきかくかくしかじかの事について電話したんだけど、ウィリアムって人がすごい、いい人で、親切に教えてくれたんだよね。別の質問があるんだけど、ウィリアムと替わってもらえる?」

「かしこまりました。ただ今ウィリアムが空いているかどうか調べますので少々お待ち下さい」 製品サポートの社員は、サポート記録から、先ほどの電話を取った人の名前を調べました。billg。

「あ、いや、うーむ。すまん、ウィリアムってのはちょっと今出られないみたいなんだな。みんな奴のことはビルって呼んでるんだよ。いやなに、あれでね。さっきおたくと話したのは誰かって? ビル・ゲイツさ」

「何ィッ?」

lambda 完全解説

目的

この記事は、C++0xのlambdaを完全に解説せんとする目的を以て書かれた。サンプルコードは最小に留め、エラー処理等は省いた。この記事さえ読めば、今日からlambdaを恐れることなく使う本物のC++0xプログラマになれるだろう。

lambdaとは何ぞや

lambdaである。あるものは、lambda関数、あるいは無名関数という名称を使っている。いったいlambdaとは何なのか。

lambdaは関数である。また、特に名前はない。したがって、lambda関数、無名関数と呼ぶのは、間違ってはいない。しかしここでは、単にlambdaと呼ぶことにする。

lambdaを定義しよう

lambdaは関数オブジェクトである。lambdaは関数オブジェクトである。これはとても大事なので二度書いた。lambdaは関数オブジェクト以外の何物でもない。ところが不思議なことに、皆lambdaが単なる関数オブジェクトであることを承知してくれない。そこで今回は、コードで多くを語りたいと思う。

int main()
{
    [](){} ;
}

このコードは、well-formedなlambdaの最小のコードである。例しにコンパイルしてみるとよい。問題なくコンパイル出来るはずである。[](){} とあるのが、lambdaである。しかし、これはただ、lambdaという関数を定義しているだけなのだ。

lambdaを呼び出そう

lambdaは関数オブジェクトであるので、当然、関数呼び出しができる。関数呼び出しの文法は、通常の関数と同じく、()である。

int main()
{
    [](){}() ;
}

lambdaの文法解説

では、詳しい解説をして行きたいと思う。

int main()
{
    []  //  [ lambda-capture ]
    ()  //  ( parameter-declaration-clause )
    {}  //  compound-statement
    ()  //  Function call expression
    ;
}

まず、一番始めの[]は、lambda-introducerという。[]のなかには、lambda-captureを記述できる。これについては、後に解説する。
二番目は、関数の引数の定義である。通常の関数で、void f(int a, int b) などと書く引数と、まったく同じである。
三番目は、関数の本体である。通常の関数と同じく、実際のコードはこの中に書く。
四番目は、関数呼び出しである。これも、通常の関数とまったく変わらない。

実は、lambdaの引数は省略できるので、本当のlambdaの最小のコードは、以下の通りである。

int main()
{
    []{} ;
}

Hello,World

さて、関数オブジェクトを呼び出すからには、何か意味のあることをさせたい。そこで、lambdaに、Hello,Worldと表示させることにしよう。

int main()
{
  []{ std::cout << "Hello,World" << std::endl ; }() ;
}

そろそろ、lambdaも単なる関数オブジェクトであることが、分かってきたかと思う。

変数に代入

lambdaは関数オブジェクトである。これを承知できないのは、文法が少し変わっているからに過ぎないのだ。lambdaは関数オブジェクトであるが故に、変数に代入できる。

int main()
{
  // 変数へ代入
  auto func = []{ std::cout << "My hovercraft is full of eels." << std::endl ; } ;

  // 呼び出し
  func() ;
}

関数の引数に渡す

また、別の関数に渡せる。

template < typename Func >
void f( Func func )
{
  func() ;
}

int main()
{
  f( []{std::cout << "All your lambda is belong to us." << std::endl ; } ) ;
}

これで諸君も、否応なくlambdaが関数オブジェクトであることを認識できたであろう。

引数を取る

lambdaは関数オブジェクトであるので、引数を取れる。

int main()
{
  [](std::string const & str)          // 引数
  { std::cout << str << std::endl ; }   // 関数本体
  ("Have you read your SICP today?") ;  // 関数呼び出し
}

戻り値を返す

lambdaは関数オブジェクトであるので、戻り値を返せる。

int main()
{
  // 戻り値は、明示的に書かなくても推測してくれる
  auto a = []{ return 0 ; }() ;

  // 戻り値を明示的に書いた場合。
    // doubleからfloatへの型変換をしている。
  auto b = []() -> float { return 3.14 ; }() ; 
}

この、->、という記述は、少し戸惑うかもしれないが、こういう文法になっているので、仕方がないのである。

lambda関数では、戻り値は明示的に書かなくても、推測してくれる。ただし、{ return expression ; }の形でなければならない。この形でない場合は、void型を返すと見なされる。戻り値を明示する場合は、たとえ引数を取らないlambdaでも、引数リストを省略することは出来ない。

変数のキャプチャ

さて、ここまで読み進めれば、lambdaが関数オブジェクトであることは、疑いようもなく理解できたと思う。しかし、ここで一つ疑問がある。「なぜlambdaなのだ。なぜもっと他の、分かりやすい名称ではないのだ」と。もっともな疑問である。lambdaをlambdaたらしめる、最も重要な機能を解説しよう。

lambdaは、その定義されている関数のスコープ内の変数を、キャプチャできる。これも、文章で説明するのは分かりにくい。例を示す。

int main()
{
  std::string x = "I'm a lumberjack and I'm OK." ;

  // 参照によるキャプチャ
  [&]{ std::cout << x << std::endl ; }() ;
  
  // コピーによるキャプチャ
  [=]{ std::cout << x << std::endl ; }() ;
}

キャプチャには二種類ある。参照によるキャプチャと、コピーによるキャプチャである。参照というのは、lambdaのオブジェクト内で、変数の参照を保持するものである。コピーとは、lambdaのオブジェクト内で、変数そのものをコピーして保持するものである。その結果、lambdaが定義されている関数内のスコープにある変数を、lambdaの中で使うことが出来る。

例えば、以下のように使える。

template < typename Func >
void f( Func func )
{
  func(" and I'm OK.") ;
}


int main()
{
  std::string x = "I'm a lumberjack" ;

  f( [&](std::string const & str){ x += str ;} ) ;

    // 変数が書き換わっている。
    // "I'm a lumberjack and I'm OK."
  std::cout << x << std::endl ;
}

コピーの場合はどうだろうか。

template < typename Func >
void f( Func func )
{
  func(" and I'm OK.") ;
}


int main()
{
  std::string x = "I'm a lumberjack" ;

    // Error
    f( [=](std::string const & str){ x += str ;} ) ;

  std::cout << x << std::endl ;
}

コピーの場合は、エラーになってしまう。何故ならば、lambdaの関数呼び出し演算子は、const修飾されているからだ。もし、どうしてもコピーのキャプチャで、変数を書き換えたいのならば、mutableが使える。

template < typename Func >
void f( Func func )
{
  func(" and I'm OK.") ;
}


int main()
{
  std::string x = "I'm a lumberjack" ;

  f( [=](std::string const & str) mutable { x += str ;} ) ;

    // コピーなので、変数は書き換わっていない。
  // "I'm a lumberjack"
  std::cout << x << std::endl ;
}

mutableは、引数リストの後、戻り値指定の前に記述する。

[]() mutable -> {} ;

キャプチャを、コピーか参照のどちらでするかは、個々に指定できる。

int main()
{
  int a = 0, b = 0 ;

  [a, &b]() mutable { a = 1 ; b = 1 ; }() ;

  // 0
  std::cout << a << std::endl ;
  // 1
  std::cout << b << std::endl ;
}

このように、変数を列挙すればいい。また、一部の変数だけを指定して、残りはひとまとめに指定したい場合、capture-defaultを指定すればよい。

int main()
{
  int a, b, c, d, e, f, g ;

  // a, bのみコピー、その他は参照
  [&, a, b] { } ;

  // a, bのみ参照、その他はコピー
  [=, &a, &b] { } ;

}

ただし、デフォルトのキャプチャと同じものを指定することは出来ない。

int main()
{
  int a, b ;

  // Error. デフォルトと同じ
  [&, &a] { } ;

  // Error. デフォルトと同じ
  [=, a] { } ;

}

同じ変数を複数書くことは出来ない

int main()
{
  int a;

  // Error. aを二度書いている。
  [a, a] { } ;
}

this

クラスの非静的なメンバ関数内のlambdaで、thisを使った場合、そのクラスのオブジェクトのthisになる。

struct X
{
  int a ;
  void f()
  {
    [=]{ this->a = 1 ;}() ;
  }
} ;

thisはポインタであるので、この場合、キャプチャがコピーでも参照でも、aは書き換わる。

lambdaを返す関数

lambdaは関数の戻り値として返すことも出来る。

std::function< void () > f()
{
  std::string str("hello") ;
  return [=]{ std::cout << str << std::endl ; } ;
}

int main()
{

  // 一度変数に代入してから呼び出す。
  auto func = f() ;
  func() ;

  // lambdaを変数に代入せずそのまま呼び出す。
  f()() ;

}

このように、C++0xで追加された、すばらしい標準ライブラリ、std::functionを使えば、lambdaを返すことが出来る。

キャプチャが参照ではなくコピーであることに注意されたい。f()が戻る時点で、strは破棄されるので、ここはコピーでなくてはならない。

lambdaの型

規格では、lambdaは、ユニークな型を持つと定義されている。ただし、以下のコードはエラーである。

// Error
decltype([]{}) ;

これを出来るようにすると、コンパイラの実装が難しくなるからだ。同じ理由で、sizeofも使えない。

lambda実践

コードは文章よりも分かりやすい。

struct X
{
  int value ;
} ;

int main()
{
  std::vector< X > v(20) ;

  std::mt19937 rng ;
  std::uniform_int_distribution<int> dist(1, 99) ;

  // 乱数で初期化
  std::generate( v.begin(), v.end(),
    [&]() -> X {
      X x ;
      x.value = dist( rng ) ;
      return x ;
    }
  ) ;

  // 表示
  std::for_each( v.begin(), v.end(),
    [](X const & x)
            { std::cout << x.value << " " ; }
  ) ;
  std::cout << std::endl ;

  // ソート
  std::sort( v.begin(), v.end(),
    [](X const & a, X const & b)
            { return a.value < b.value ; }
  ) ;

  // 表示
  std::for_each( v.begin(), v.end(),
    [](X const & x){ std::cout << x.value << " " ; }
  ) ;
  std::cout << std::endl ;
}

最後に

結局の所、lambdaとは、ちょっと便利な関数オブジェクトに過ぎないのである。C++で関数オブジェクト使うのは常識であるから、C++0xでlambdaを使うのも常識になるだろう。

2009-11-23

rvalue reference 完全解説

目的

この記事は、C++0xのrvalue referenceを完全に解説せんとする目的を以て書かれた。サンプルコードは最小に留め、エラー処理等は省いた。この記事さえ読めば、今日からrvalue referenceを恐れることなく使う本物のC++0xプログラマになれるだろう。

lvalueとrvalueについて

Cの時代では、lvalueとrvalueの違いは、代入演算子の左側か右側かという違いだけであった。つまり、left hand value, right hand valueの略である。従って、訳語も、左辺値、右辺値であった。C++においては、これはもはや正しくはない。従って、右辺値、左辺値というのも、誤訳である。それ故に、ここでは、これ以上、左辺値、右辺値という名称を使用しない。

誤解を恐れずにいえば、lvalueとは、明示的に実体のある、名前付きのオブジェクトであり、rvalueとは、一時的に生成される無名のオブジェクトである。

struct X{} ;
int f() { return 0 ; }

int main()
{
  int i = 0 ;

  i ;   // lvalue
  0 ;   // rvalue

  X x ;

  x ;   // lvalue
  X() ;  // rvalue

  f() ;  // rvalue
}

上記のコードを読めば、lvalueとrvalueの違いが、なんとなく分かってくれる事と思う。lvalueはrvalueに変換できるが、その逆、rvalueをlvalueに変換することは出来ない。

referenceについて

C++98のreferenceは、C++0xにおいては、lvalue referenceと呼ばれるものである。

struct X{ } ;

void f( X & ) { }
void g( X const & ) { }

int main()
{
  X x ;

  f( x ) ;  // 1. OK
  f( X() ) ; // 2. Error

  g( X() ) ; // 3. OK
}

1.は問題がない。lvalueだからだ。
2.はコンパイルエラーになる。rvalueを渡しているからだ。
3.は問題がない。constなreferenceは、rvalueを参照できるからだ。

ちなみに、VC++の独自拡張(/Zaで無効にできる)では、2.のコンパイルが通ってしまうので注意されたい。真のC++プログラマは、コンパイラを信用しないものである。

ここで、3.は、言語的には、汚い仕様である。本来、rvalueなものを、lvalue referenceで参照しているのである。そこで、rvalue referenceの出番となる。

Rvalue Reference

rvalue referenceとは、その名の通り、rvalueに対する参照である。文章で説明するより、コードを示した方が分かりやすい。

struct X{ } ;

int main()
{
  X x ;

  // lvalue reference
  X & lr1 = x ;    // 1. OK
  X & lr2 = X() ;   // 2. Error

  // rvalue reference
  X && rr1 = x ;   // 3. Error
  X && rr2 = X() ;  // 4. OK
}

ごらんのように、rvalue referenceは、アンパサンドを二つ使う文法になっている。

1. は問題ない。xはlvalueだからだ。
2. はコンパイルエラーである。X()はrvalueであり、lvalue referenceでは参照できないからだ。
3. はコンパイルエラーである。xはlvalue referenceであり、rvalue referenceでは参照できないからだ。
4. は問題ない。X()はrvalueだからだ。

Rvalue Referenceの存在意義

実は、rvalue referenceとは、これだけの事なのである。その名前通り、rvalueに対する参照なのだ。とはいっても、これだけでは、存在意義が分からないであろうと思う。「一体何の役に立つのだ? const lvalue referenceでなくてもrvalueを参照できるようになっただけではないか?」と思うことだろう。実際、その通りで、「const lvalue referenceでなくてもrvalueを参照できるようになる」だけなのである。

そもそも、rvalueのオブジェクトには名前がなく、参照されなくなった時点で、自動的に破棄されるものである。勝手に破棄されるなら、書き換えても無駄である。constではなくなったからといって、何がそんなに嬉しいのか。

Move Semantics

以下のようなクラスを考える。

class X
{
private :
  char * ptr ;

public :
  X()
  {
    ptr = new char[1000] ;
    // バッファに対して、時間のかかる書き込みを実行
  }

  // コピーコンストラクタ
  X( X const & r )
  {
    ptr = new char[1000] ;
    std::copy( &ptr[0], &ptr[1000], &r.ptr[0] ) ;
  }

  // デストラクタ
  ~X()
  {
    delete[] ptr ;
  }

} ;

このクラスは、明らかにコンストラクタとコピーコンストラクタの実行が遅い。もし、コピーコンストラクタを、ポインタのすげ替えだけにすれば、パフォーマンスが大いに向上するだろう。ところが、そんなことをしてしまっては、コピー元のオブジェクトが使えなくなってしまうので、それは出来ない相談である。

しかし、よく考えると、安全に、コピーをポインタのすげ替えだけで済ませられる場合が存在するのである。

struct X {} ;

X f(){ return X() ; }

int main()
{
    // 関数の戻り値はrvalueである。
    X a( f() ) ; // 1.
    
    X tmp ; 
    X b( tmp ) ; // 2.

    // これ以降、tmpはもう使わない。
}

ここで、関数の戻り値はrvalueなので、安全にポインタをすげ替えられる。また、tmpは、もうこれ以上使わないので、ポインタをすげ替えても差し支えない。問題は、一体どうやって、その意図を表現すればいいのだろうか。

そこで、rvalue referenceの出番である。rvalueであれば、そのオブジェクトは、ポインタを横取りしても問題ないのである。

Move コンストラクタ

1. のコピーを、ポインタのすげ替えにするために、クラスXに、rvalue referenceを引数に取るコンストラクタを追加する。

class X
{
public :

    // Move コンストラクタ
  X( X && r )
  {
    ptr = r.ptr ;
    r.ptr = nullptr ;
  }
} ;

これをmoveコンストラクタと呼ぶ。1. は、このmoveコンストラクタが呼ばれ、ポインタのすげ替えになる。コピー元のオブジェクトのポインタを、nullptrにするのを忘れないこと。さもなくば、デストラクタが走る際に、ランタイムエラーになるだろう。

lvalueをmoveせよ

さて、2. はどうしたらいいだろう。moveコンストラクタを実装したものの、コンパイラは2. の場合には、moveコンストラクタを呼び出してくれない。なぜなら、コンパイラは、プログラマの脳内仕様を読んではくれないからだ。tmpが、その後に使われていないかどうかは、コンパイラは静的に決定できないのである。

そこで、プログラマが意図を伝えてやらなければならない。

X b( static_cast<X &&>(tmp) ) ;

この様に、rvalueにキャストしてやれば、moveコンストラクタを呼び出すことが出来る。

std::move()

とはいえ、これは甚だしく面倒である。タイプミスもしやすい。そこで、標準ライブラリには、便利な関数が用意されている。std::move()だ。

X b( std::move(tmp) ) ;

何のことはない、std::move()とは、本質的にはキャストなのである。実装例を以下に示す。

namespace std {

template <class T>
inline
typename std::remove_reference<T>::type&&
move(T&& t)
{
  return static_cast< std::remove_reference<T>::type&& >(t) ;
}

}

これだけの事なのである。単なるキャストである。自前でキャストを書くのは、エラーの元なので、std::move()を使うべきである。

ひとたび、変数に対してstd::move()を呼び出すと、それ以降、その変数を使える保証はなくなる。なぜなら、すでにmoveされているかもしれないからだ。

賢いコンパイラの場合

ちなみに、コンパイラによっては、上記のコードは、そもそもコピーコンストラクタもmoveコンストラクタも呼び出されない可能性がある。というのも、ある種の状況においては、コンパイラは安全且つ静的に、オブジェクトをコピーせずに、使い回せることを決定できるのである。たとえコンストラクタにサイドエフェクトがあったとしても、コンストラクタの呼び出しを省略できるのである。この種の最適化は、規格で保証されている。
(N3000 § 12.8 Copying class objects p19)

手持ちのコンパイラが優秀で、上記のコードでは、コンストラクタが呼び出されない場合、rvalue referenceの勉強のためには、以下のように書くとよい。

class X
{
public ;

    // moveな代入演算子
  X & operator = (X && r)
  {
    if ( this == &r )
      return *this ;

    delete[] ptr ;

    ptr = r.ptr ;
    r.ptr = nullptr ;

    return *this ;
  }
} ;

int main()
{
    X tmp ;
    X x ;
    
    x = std::move(tmp) ;
   
}

これは、最適化できないはずである。また、実際のコードではこのように、movableにしたければ、move コンストラクタの他に、move 代入演算子も定義するべきである。

オーバーロード

lvalue referenceとrvalue referenceは、もちろん、関数のoverload resolutionの際に、考慮される。

struct X {} ;

void f( X & x )
{ std::cout << "lvalue reference" << std::endl ; }

void f( X && x )
{ std::cout << "rvalue reference" << std::endl ; }


int main()
{
  X x ;

  f( x ) ;  // lvalue reference
  f( X() ) ; // rvalue reference
}

これは、さほど驚くに当たらないだろう。なぜなら、lvalueかrvalueかは、コンパイル時に静的に決定できるのだから。

テンプレート関数の引数におけるrvalue referenceのargument deduction

テンプレート関数の場合はどうなるだろうか。以下のコードを考えてもらいたい。

struct X {} ;

template < typename T >
void f( T && t ) {}

int main()
{
  X x ;

  f( x ) ;  // lvalue reference
  f( X() ) ; // rvalue reference
}

果たして、これはコンパイルが通るのだろうか。

実は、このコードはコンパイルが通る。規格には特別なルールがあり、テンプレート引数を、rvalue referenceとして関数の引数に使った場合のargument deductionで、lvalueを渡すと、lvalue referenceとなるのである。
(§ 14.9.2.1 Deducing template arguments from a function call p3)

つまり、上記のコードの場合、f()に、lvalue referenceを渡すと、TがX &になり、続く&&は無視され、lvalue referenceとして取り扱われる。

実に不思議なルールである。しかし、これも理由あってのことなのだ。もし、これが出来ないとなると、プログラマは、わざわざ、lvalue referenceとrvalue referenceとで、似たようなコードを複数書かなければならなくなる。すべての組み合わせを網羅するには、膨大なオーバーロード関数が必要になる。引数が1個の場合は、オーバーロード関数は2個、引数が2個の場合は、4個、引数が3個の場合は、8個、引数が4個の場合は、16個もの、オーバーロード関数を書かなければならない。これでは、一体何のためのテンプレートなのだろうか。

幸いなことに、テンプレート関数の場合は、rvalue referenceでlvalue referenceも参照できるので、そのようなオーバーロード関数の指数関数的な増加は起こらない。しかし、ここでひとつ問題がある。

Perfect Forwarding

template < typename T >
void f( T && t )
{
  X x(t) ;
}

f()の中で、Xをコピーしたい。ここまで読み進めた者ならば、当然、rvalueの際には、moveしたいところであろう。ところが残念なことに、std::move()は使えないのである。

なぜだろうか。

struct X {} ;

template < typename T >
void f( T && t )
{
  X x( std::move(t) ) ;
    // これ以降、tは使用不可
}

int main()
{
  X x ;

  f( x ) ;  // lvalue reference

  //これ以降、xは使用不可
}

なぜなら、引数はlvalue referenceである可能性もあるからだ。main()側で、std::move()していないのに、xが勝手にmoveされて使用不可になったのでは、たまったものではない。main()側でstd::move()したときのみ、moveしてもらいたい。

ところが、f()側からみれば、引数はlvalueかrvalueか、テンプレートがインスタンス化されるまで分からないのである。lvalue referenceならコピーし、rvalue referenceの時のみmoveしたい。さて困った。一体どうしよう。

メタプログラミングを試す

メタプログラミングである。メタプログラミングの理解出来ないプログラマは、もはやC++プログラマとして認められないのである。ポインタの理解できないCプログラマと同じぐらい、役立たずのゴミ虫のすかしっ屁である。メタプログラミングこそ正義ィィッ! メタプログラミングに不可能はないィィッ!

では、さっそくメタプログラミングで問題を解決しようッ!

template < typename T >
void f( T && t )
{
  if ( std::is_lvalue_reference<T>::value )
    X x( t ) ;
  else
    X x( std::move(t) ) ;
}

残念ながら、これは問題を多数のオーバーロード関数から、多数のメタプログラムに移しただけである。引数をひとつひとつ、このような方法で調べていくのは、面倒だし、引数が増えれば、オーバーロード関数と同じく、if文も爆発的に増えていく。

必要なのは、lvalueの場合はlvalue、rvalueの場合はrvalueを渡す方法である。

キャストを使う

以下のようなキャストを使えば、それが実現できる。

template < typename T >
void f( T && t )
{
  X x( static_cast<T &&>(t) ) ;
}

なぜこのキャストが、lvalueの時はlvalueを返し、rvalueの時はrvalueを返すのか。それは、argument deductionのおかげである。

もし、引数にlvalueが渡された場合、TはX &となり、&&は無視される。それ故、このキャストは、lvalueをlvalueにキャストするのである。rvalueが渡された場合は、当然、rvalueとなる。

このようにすれば、テンプレート関数に渡された引数を、そのまま別の関数に渡すことが出来る。

std::forward()

とはいえ、キャストを使うのは面倒であるし、エラーの元である。そのために、標準ライブラリには、便利な関数が用意されている。std::forward()だ。

template < typename T >
void f( T && t )
{
  X x( std::forward<T>(t) ) ;
}

何のことはない。std::forward()とは、本質的にはキャストなのである。実装例を以下に示す。

namespace std {

template <class T, class U,
  class = typename enable_if<
     (is_lvalue_reference<T>::value ?
       is_lvalue_reference<U>::value :
       true) &&
     is_convertible<typename remove_reference<U>::type*,
            typename remove_reference<T>::type*>::value
  >::type>
inline
T&&
forward(U&& u)
{
  return static_cast<T&&>(u);
}

}

恐ろしげなメタプログラムに面食らうかも知れないが、本質的には単なるキャストである。メタプログラムの意味は、
Tがlvalue referenceならば、Uもlvalue referenceでなければならない。
参照を取り除いた状態で、UからTに変換できなければならない。
という意味である。この二つの条件を満たさない場合、std::forward()はoverload resolutionのcandidateから外される。則ち、コンパイルエラーとなる。これにより、典型的なタイプミスなどによるエラーを防ぐことが出来るのである。

std::forward()は、テンプレート関数の引数を、田の関数にそのまま渡す際に使うものである。これをPerfect Forwardingという。

最後に

rvalue referenceは、実に単純なのである。名前の通り、rvalueへの参照に過ぎないのである。std::move()もstd::forward()も、単なるキャストに過ぎないのである。

std::move()は、lvalueをmoveしたいときに使い、std::forward()は、テンプレート関数の引数を、そのまま別の関数に渡したい時に使う。