2014-03-31

2014-02-post-Issaquahのレビュー: N3920-N3929

前回同様、2014-02-post-Issaquahを引き続きレビューしていく。今回は、N3920からN3929までだ。N3966まであるので、すこし先が見えてきた。

N3920: Extending shared_ptr to Support Arrays, Revision 2

shared_ptrで配列を直接にサポートする拡張案。

現在、shared_ptrで配列へのポインターを扱うには、カスタムデリーターを書いて指定する必要があった。そんな面倒なことをしなくても、shared_ptr<T[]>やshared_ptr<T[N]>を認識して、デリーターを適切に選択してくれるように変更する提案だ。

前回のN3869からの変更点は、特筆すべきでもない細かな文面変更にとどまるようだ。

N3921: string_view: a non-owning reference to a string, revision 7

文字列を、実装の詳細を隠匿して、通過的に扱うためのライブラリ、string_viewの提案の文面案。

文字列を表現する方法として一般的なのが、charなどの文字型の配列と、文字数のペアである。文字列クラスというのは、標準ライブラリにもあるし、また標準ライブラリが目的に合わない場合は、自作されるこのような文字列の実装の詳細を隠して、文字列にアクセスできるラッパークラスが、string_viewだ。

string_viewは、std::basic_stringとほぼ互換のあるメンバーを備えていて、basic_stringのように扱うことができる。

前回の論文からの変更点は、それほど特筆すべきものはない。興味のある読者は、直接論文を読んでもらいたい。

N3922: New Rules for auto deduction from braced-init-list

N3912の提案のための規格の文面案。

[江添フレンドリーとは真逆の存在であるPDF] N3923: A SFINAE-Friendly std::iterator_traits, v3

[PDF注意] N3909によるstd::iterator_traitsをSFINAEフレンドリーにする提案の規格文面案。

[PDFの利用も非推奨扱いにするべき] N3924: Discouraging rand() in C++14, v2

C++11で、新しい乱数ライブラリが導入されたことにより、既存のC時代から受け継いだrand, srand, RAND_MAXと、std::random_shuffleの使用を非推奨扱いにする提案の文面案。

C++11では、より優れた乱数生成と乱数分布のためのライブラリが追加されたので、従来の使いづらく誤用されやすい劣ったrand, srand, RAND_MAXは、規格で使用を推奨しない強いNOTE(注記)を追記する。

std::random_shuffleは、randに依存するオーバーロードがある。また、この関数に独自の乱数生成器を渡す際にも、そのインターフェースが極めて使いづらい。C++11では、新しく設計が洗練されたstd::shuffleが追加されたので、std::random_shuffleもdeprecated扱いにする。

論文では、文面案も示している。

[PDFは採取する必要がない] N3925: A sample Proposal, v4

値の集合の中から、ランダムで標本を採取するアルゴリズム、std::sampleの提案。値がいくつあるかわからなくても正しく採取できる。

もともと、SGI STLにsample, sample_nとして存在したアルゴリズム。提案では、別の名前に分けずに、オーバーロードで切り分ける設計になっている。

そのリファレンス実装も論文に書かれているが、50行程度なので、ここに貼れるほど短い。

// リファレンス実装
template< class PopIter, class SampleIter, class Size, class URNG >
SampleIter
sample( PopIter first, PopIter last
      , SampleIter out
      , Size n, URNG&& g
)
{
    using pop_t = typename iterator_traits<PopIter>::iterator_category;
    using samp_t = typename iterator_traits<SampleIter>::iterator_category;

    return __sample( first, last, pop_t{}
                   , out, samp_t{}
                   , n, forward<URNG>(g)
                   );
}

template< class PopIter, class SampleIter, class Size, class URNG >
SampleIter
__sample( PopIter first, PopIter last, input_iterator_tag
        , SampleIter out, random_access_iterator_tag
        , Size n, URNG&& g
)
{
    using dist_t = uniform_int_distribution<Size>;
    using param_t = typename dist_t::param_type;
    dist_t d{};

    Size sample_sz{0};
    while( first != last && sample_sz != n )
        out[sample_sz++] = *first++;

    for( Size pop_sz{sample_sz}; first != last; ++first, ++pop_sz ) {
        param_t const p{0, pop_sz};
        Size const k{ d(g, p) };
        if( k < n ) out[k] = *first;
    }
    return out + sample_sz;
}


template< class PopIter, class SampleIter, class Size, class URNG >
SampleIter
__sample( PopIter first, PopIter last, forward_iterator_tag
        , SampleIter out, output_iterator_tag
        , Size n, URNG&& g
)
{
    using dist_t = uniform_int_distribution<Size>;
    using param_t = typename dist_t::param_type;
    dist_t d{};

    Size unsampled_sz = distance(first, last);
    for( n = min(n, unsampled_sz); n != 0; ++first ) {
        param_t const p{0, --unsampled_sz } ;
        if( d(g, p) < n ) { *out++ = *first; --n;}
    }

    return out;
}

前回の論文からの変更に、特筆すべきものはないようだ。

[PDFはdefect] N3926: LWG Issue 2168 is NAD

Library issue 2168はNAD(Not A Defect、問題ではない)と結論する論文。

26.5.8.22 p1では、uniform_real_distributionは、\(a \leq x < b\) の範囲に分布する乱数を生成するとある。

26.5.8.22 p2では、uniform_real_distribution( RealType a = 0.0, RealType b = 1.0 ) ;とあり、\( a \leq b \) かつ \(b - a \leq \verb=numerix_limits<RealType>::max()=\) でなければならないとしている。

この文面では、aとbの差が表現可能ではない場合(最もわかりやすい例はa == b)では、26.5.8.22を満たせないではないか。なぜ半開区間なのか。

まず、この文面はもともと\(a < x < b\)だった。しかし、プログラマーというものは、 統計学者や数学者と違い、閉区間ではなく、半開区間を好むものであるので、\(a \leq x < b\)に修正された。issue 2168はこの背景をしらずに追加されたというのがまず一点。

\(a \neq b\)である理由は、\(1 / (b - a)\)を計算する必要があるためである。したがって、\(a \neq b\)である引数を与えるのは、利用者側の責任であるとのことだ。

ただし、\(a \neq b\)が要求されるのは、operator ()を呼び出した時だ。uniform_real_distributionのオブジェクトを\(a = b\)の条件で初期化しても、問題はない。

N3927: Definition of Lock-Free

C++ Standard Library Active Issues 2075を解決するための文面案。

Library issue 2075は、規格の以下の文面を問題としている。

1.10 [intro.multithread] p2

Implementations should ensure that all unblocked threads eventually make progress.

C++の実装は、ブロックされていないスレッドは、いずれ実行が進むことを保証したほうがよい。

ちょっとまて。これを文字通り解釈して保証しようとすると、大変なことになるぞ。アトミック操作にロックフリー程度の保証では実現できないぞ。アトミック操作は、一部のスレッドの実行が進むことを保証するだけだからだ。

そもそも、実行が進む(make progress)とはどういう意味だ。「ブロックされていないスレッド」には、現在ロックされているスレッドは含まれないのか(そうであれば、アトミック操作がロックフリーであるだけで十分なはずだが)

29.4 [atomics.lockfree] p2で、ロックフリー(Lock-free)という用語が使われているが、ロックフリーなる用語の定義がないぞ。そして、議論の結果、どうやらC++規格の文面で使われているロックフリーという用語は、一般的なロックフリーとは意味が異なるものであるぞ。

この問題を解決するために、「ロックフリー」という言葉を定義することにした。文面案は以下の通り

Executions of atomic functions that are either defined to be lock-free (29.7 [atomics.flag]) or indicated as lock-free (29.4 [atomics.lockfree]) are lock-free executions.

ロックフリーと規定されている、もしくはロックフリーであると示唆されているアトミック関数の実行はロックフリー実行である。

  • If there is only one unblocked thread, a lock-free execution in that thread shall complete. [Note: Concurrently executing threads may prevent progress of a lock-free execution. For example, this situation can occur with load-locked store-conditional implementations. This property is sometimes called obstruction-free. —end note]
  • When one or more lock-free executions run concurrently, at least one should complete. [Note: It is difficult for some implementations to provide absolute guarantees to this effect, since repeated and particularly inopportune interference from other threads may prevent forward progress, e.g. by repeatedly stealing a cache line for unrelated purposes between load-locked and store-conditional instructions. Implementations should ensure that such effects cannot indefinitely delay progress under expected operating conditions, and that such anomalies can therefore safely be ignored by programmers. This property is sometimes called lock-free outside this International Standard. —end note]
  • ブロックされていないスレッドがひとつだけ存在する場合、そのスレッド内におけるロックフリー実行は完了しなければならない。[注:平行に実行されているスレッドはロックフリー実行を妨げるかもしれない。たとえば、load-locked store-conditionalな実装をしている場合におこる。このような特徴を、時に、obstruction-freeと言う。注終わり]
  • ひとつかそれ以上のロックフリー実行が平行に実行する場合、少なくとも、ひとつは完了するべきである。[注:一部の実装では、この効果を完全に保証するのは難しい。というのも、他のスレッドからの連続して特に間の悪い干渉が、実行の進展を妨げるかもしれないからである。例えば、load-lockedとstore-conditional命令の間で、キャッシュラインを奪い合う場合。実装は、通常の実行の条件下において、このような効果が、永久に実行の進展を妨げないように保証すべきである。それにより、余りの異常な条件は、プログラマーは安全に無視できる。このような特徴を、時に、この国際規格の範疇の外では、ロックフリーと呼んでいる。注終わり]

[PDFを省略したい] M3928: Extending static_assert, v2

static_assertの2つ目の文字列を省略できるようにする提案。

// N3928提案
static_assert( true )

[PDFで論文を公開すべきではない] N3929: Concepts Lite Specification

Concept LiteのTSドラフト

軽量コンセプトについては、TSが正式に出たときに、詳細な解説記事を書きたい。

TSなので、たたき台に過ぎないのだが。

ドワンゴ広告

この記事はドワンゴ勤務中に鳩サブレーを食べながら書かれた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

LenovoのThinkpad X60を手に入れた

LenovoのThinkpad X60を格安で手に入れた。

基本的なスペックとしては、CPUがIntel Core Duoで、メモリがDDR2の1.5GB、GPUはIntel Media Accelerator 950、HDDはSATA接続で、容量は80GB。ディスプレイのサイズは12.1インチで、解像度は1024x768。1Gb Ethernetはあるものの、USB 2.0ポートしかない。

スペックは今からみれば使い物にならないほど低いが、何しろ格安で入手できたので、おもちゃにちょうどいい。さて、どう料理してくれようか。

まず、メモリーとストレージ容量が低いという問題がある。しかし、わざわざ金を払って、いまさら2GBのDDR2を二枚購入したり、1TBの2.5インチHDDや128GBのSSDを購入して換装するのは、なにか違う気がする。これはこのまま活用すべきであろう。

まず、Ubuntu 13.10 64bit版をインストールしようとしたが、なぜかインストーラーが動かない。おそらく、メモリ不足のために、OOM Killerが仕事をしてしまっているのではないかと思う。32bit版ならインストールできた。

ところで話は変わるが、同居人に、英語を学びたい意欲を示している者がいる。自ら学ぶ意欲を示した者には、環境を与えてやらなければならない。私が多数の人間の善意によって支援を受けてここまでやってきたので、その恩は、次の世代を育てることで返さなければならない。

色々と考えた挙句、NHKのラジオ英語講座を受けさせるのがいいだろうと判断した。本人は、中学程度の英語なら理解していると主張しているが、実際にみてみると、be動詞や時制すらできていないので、やはり基礎からやり直す必要があると判断した。

基礎英語1のテキストとともに、私が英語を学び始めた時にぜひとも読みたかった本、 ビッグ・ファット・キャットの世界一簡単な英語の本を与えた。この本はとても良い本であるが、残念ながらこの本が出版されたときには、筆者はすでに英語をある程度理解してしまったあとであったので、この本は筆者のためには、それほど役に立たなかった。しかし、この本は良い本であることには変わりない。

それから、神保町を回って、捨て値で売られていた研究社の英和、和英辞書、そしてLONGMAN英英辞書を買ってきた。

幸いこの同居人は、洋楽が好きなので、最低限の英語に触れる環境にあった。また、中学高校と、公教育の授業では真面目に学んでいたので、完全に英語を知らないわけでもない。そして、まだ若い。まだ希望はあるだろう。

さて、この同居人は、コンピューターを持っていなかったので、このUbuntuをインストールしたX60を与えてみた。何の環境構築もしていないので、日本語すら入力できない。UIも英語だ。英語と自由ソフトウェアを学ぶにはいい環境だろう。

残念ながら、この同居人は、コンピューターには興味を示さなかったので、X60は回収した。何かを学ぶには、その学ぶべき対象に興味を持つ必要がある。コンピューターに興味を示さない以上、コンピューターからは学べないだろう。強制的に教えても身につかない。同居人は、コンピューター以外のものから英語に触れる必要があるだろう。

さて、そんなわけで、X60が手元にある。とりあえずは来客が手軽にWeb閲覧をする共用端末としてもいいのだが、なにか活用してみたい。

あるいは、手頃なNASとして扱おうか。ラップトップは電力消費が低く、また実質UPSが組み込まれているようなもので、家庭用のお手軽自作NAS用としては優れているのではないか。ただし、内臓のHDDは80GBしかないし、2.5インチだ。USB接続のHDDをつけようにも、USB 2.0という問題がある。どうせ自作するならば、秋葉原で叩き売られている中古PC(1Gb EthernetかつSATAポートが数個はあるやつ)を買ってきたほうがいいのかも知れない。

もちろん、専用のNAS製品のほうが手間がかからないし、パフォーマンスも安定しているだろう。しかし、手間がかからないということは、面白くもないということだ。工夫のしどころがない。

さて、実際に秋葉原に行って、色々と探してみたが、どうも、思ったような中古コンピューターが思ったような値段で見つからない。1万円を切るような値段で売っているコンピューターは、残念ながら私の希望する最低のスペック要件を満たせない(SATA、1000BASE-Tの有無など)

さて、どうするか。こんなことならば、実家から引っ越すときに、コンピューターを持ってくればよかったと後悔している。

とりあえず、X60にSATA-USB変換器を取り付けて、即席にNASを作ってみた。お手軽だったのでSMBを使ってみたが、どうにも不安定だ。私は不自由な二大OSであるWindowsとAppleを一切使わないし、いまはGNU/Linuxしか使っていないのだから、NFSの方がいいだろうか。

2014-03-30

ギークハウス新宿二丁目

最近東京に出てきた筆者は、自らシェアハウスにすみ、またシェアハウス巡りをしている。今回は、ギークハウス新宿二丁目に伺った。

当日は、たまたまギークハウス新宿に飲みによばれたのであった。仕事帰りに向かったのだが、筆者はたまたま、妖怪ハウスに必要なゴミ箱を六箱も抱えていたため、上腕を疲労させながら新宿まで向かった。ギークハウス新宿で飲んでいたところ、場の流れで、ギークハウス新宿二丁目に向かうことになった。

ギークハウス新宿二丁目は、名前通りに、新宿二丁目に存在する。新宿二丁目というのは、ゲイバーが立ち並ぶところであるらしい。

新宿二丁目 - Wikipedia

実際に現地を観察した所、たしかにゲイバーが多かった。

ギークハウス新宿二丁目は、ゲイバーも入っている雑居ビルの上の階に存在した。どうやら、エレベーターが設置されていない雑居ビルの上層階というのは、客が入りづらく、なかなか借り手がいないらしい。そのため、上層階が住居となることは、よくあることなのだそうだ。

さて、ギークハウス新宿二丁目の住人が言うには、私はきわめてもったいない生き方をしているという。せっかく東京に出てきて、機会に恵まれているのに、その機会を存分に活用していないという。

例えばブログだ。私のブログは、広い読者層を獲得する内容ではない。もっと広く浅く書けば、読者が増える。すなわち、私の支持者が増える。私の支持者が増えるということは、それだけ私は強い影響力を行使することができ、様々なことがやりやすくなるであろうということだ。

なるほど、確かに支持者が増え、影響力が高まれば、都合の良いこともあるだろう。しかし、そのために払う犠牲が多すぎる。

まず、広く浅く、一般受けする文章を書く力を向上させると、狭く深く書く能力が失われる。その結果、私はC++の規格の理解をおざなりにして、かわりに、猫画像に適当なキャプションをつけて公開するとか、2chのレスを自作自演してまとめるとか、本の読書感想文を投稿するなどの、よくあるアクセス数だけは稼げるブログのひとつに成り下がってしまうだろう。

広く浅く書く能力だけを鍛えると、いざ、影響力を行使できる状況になったところで、その影響力を行使すべき能力が失われてしまう。

そもそも、影響力とは何なのか。私に盲目的に従う信者の数を言うのか。それはもはや宗教である。私は人間の無謬を信じていない。私は私の周りをイエスマンで固めたいとは思わない。

なおも住人の話は続く。私は妖怪ハウスに住むべきではないという。私は、シェアハウスを運営すべきなのだという。シェアハウスを運営し、利益を上げ、その利益でプログラマーが格安で住めるシェアハウスを提供すべきなのだという。ギークハウス新宿、ギークハウス新宿二丁目、ギークハウス秋葉原の管理人のようになるべきなのだという。そうすれば、自分の才能に気がついていない、誰かからの後押しを必要としているプログラマーの才能を開花させることができるのだという。

たしかに、シェアハウスの運営は興味深い。しかし、今はまだその時ではない。私の理想は吉田寮だが、あの雰囲気を作り出すのは難しい。私がシェアハウスを立ち上げ、運営し、管理し、利益を上げる(あるいは損失をひきうける)ということは、管理者である私に不平等な権力差が発生する。自己主張をしない人間であれば、穏健的な独裁者となることも可能であろうが、私は自己主張をする。したがって、私の管理するシェアハウスは、吉田寮とはならないであろう。

それに、周りにプログラマーが多くいる環境は好ましいが、それだけでは本物のプログラマーにはなれない。本物のプログラマーとなるためには、遅くとも志学までには、プログラミングの価値を理解し、学ぶ意欲を示さなければならない。

私は、プログラミングというのは、直接物理的に対面して教えられることは少ないのではないかと思う。確かに、個々の知識を教えることはできる。しかし、やはりプログラミングの学習というのは、大部分は独学しなければならない。その独学の役に立つのが、文章だ。文章は、いつでも好きなときに読むことができる。

かつまた、ギークハウス新宿二丁目や秋葉原の住環境と家賃は、妖怪ハウスに比べて見劣りするように感じられる。これは、シェアハウスで利益を上げなければならないためである。シェアハウスを住人の自治とし、シェアハウス自体で利益を上げなければ、家賃は安く、一人では到底住めないような広い部屋に住める。

また、この住人の職歴も、私の価値観と反する。この住人は、まずSI屋に雇用されていた。設計に何年もかけ、関係者同士の調整に駆けまわるような仕事だったという。私の価値観では、このようなプロジェクトは極めて非効率的である。これは、住人も認めていた。

この住人が次に就いたのは、転職エージェントだという。転職エージェント・・・これがクセモノだ。

そもそも、エージェント(代理人)というのは、ふさわしい言葉なのだろうか。転職には、雇用者と被雇用者がいるが、いったい、転職エージェントはどちらの代理人なのだろうか。代理人は、一方の代理人であるべきであり、両方の代理人となるべきではない。しかし、どうも日本の転職エージェントは、両方の代理人として振舞っている雰囲気がある。

そもそも、転職エージェントはなぜ必要なのか。この住人が語るところによれば、それは私の価値観に真っ向から反する内容であった。

人を雇いたい企業がいる。希望する人材の条件がある。当然だ。人を雇うのであるから、有能な人材を求めているはずだ。ところが、この条件というのがクセモノだ。

企業が転職エージェントに開示する条件とは、例えば、「32歳以下の人が欲しい」、「男のみ欲しい」、「女のみ欲しい」といった、公にできない条件である。ことによっては、法律に抵触する条件である。こういった公に出来ない、ことによっては違法な条件を転職エージェントに伝える。転職エージェントはその条件を満たす人間のみに企業を紹介する、マッチングを行う。

これは、本質的には何も変わらない。もし、条件が違法であれば、間にプロキシーを一枚かませたところで、違法であることに変わりはない。条件を提示した時点で違法であるからだ。結局、転職エージェントとは、犯罪の片棒を担ぐ仕事であったのか。

そもそも、違法な条件で求人する企業である。すでに法を犯したものに、その余りの法を順守することが望めるだろうか。そのような企業は、たいてい他の法律(例えば労働基準法など)も破っているだろう。そのような企業で働くのは危険である。

かつまた、その企業は、雇用者を能力ではなく、年齢や性別で選別している企業である。すなわち、自分の同僚も同様にして、能力ではなく、単なる年齢や性別のみで選別されて雇用されているに違いない。したがって、同僚は無能である可能性が高い。この点からも、そのような目的で転職エージェントを使う企業で働くのは危険である。

また、住人は言う。転職エージェントは非雇用者にとっても有益である。なぜならば、レジュメを書くにあたって、大抵の人間は、自分を効果的にアピールすることができない。自分の本来の能力を、規程の枚数の紙面で宣伝できない。そのために、プロの指導が必要なのだ。云々

これも、私にはよくわからない。そもそも、プログラマーの能力が、そんなに簡単に紙切れ一枚の上に宣伝できるだろうか。ことプログラミングにおいては、学歴フィルターはそれほど役に立たないし、資格などというものも役に立たない。たとえ、素晴らしい研究をしたものにのみ学位が与えられるだとか、能力を正しく検定して認められる資格があったにせよ、それはその当時のことである。この移り変わりの激しいソフトウェア業界で、5年前、10年前の学位や資格が、状況の変わった今、どれほど役に立つものか。経験年数も、目安にはならない。たとえ無能を5年続けても、経験5年である。

そのようなファンシーなレジュメを追い求めると、手書きの履歴書を評価するような馬鹿げた風潮が流行る。手書きの履歴書を評価項目に加えていいのは、筆耕業者ぐらいなものだ。

こうして、議論は一切の歩み寄りをせず、平行線のまま終わった。

2014-03-28

なんでGCCはa*a*a*a*a*a を (a*a*a)*(a*a*a) に最適化できないの?っと

c - Why doesn't GCC optimize a*a*a*a*a*a to (a*a*a)*(a*a*a)? - Stack Overflow

俺は科学技術計算の数値計算の最適化をしてたんだけどさ。GCCはpow(a, 2)a*aにしてくれるんだな。うん。で、pow(a, 6)は最適化されずに、ライブラリ関数であるpowを呼んじゃうんだ。パフォーマンス的に最悪。(Intel C++ Compilerはpow(a,6)のライブラリ関数呼び出しを消し去ってくれるんだけどな)

どうもよくわからんのが、pow(a, 6)a*a*a*a*a*aで置き換えて、GCC 4.5.1をオプション"-O3 -lm -funroll-loops -msse4"で使ったら、mulsd命令を5個使う。

movapd  %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13

だが、(a*a*a)*(a*a*a)と書いたら、出力は、

movapd  %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm13, %xmm13

これは、乗算命令が3個になっている。iccもGCCとほぼ同じだ。

なんでコンパイラーはこれを最適化できないんだ?

答え:浮動小数点数演算では、結果が変わってしまうおそれがあるから。

それは、浮動小数点数は結合法則を満たさないからだ。浮動小数点乗算のオペランドの囲み方により、結果の数値精度に影響を及ぼすからだ。

その結果、ほとんどのコンパイラーは、浮動小数点数演算のリオーダリングに対して極めて保守的なのだ。答えが変わらないと確信できるときや、数値精度を気にしない場合にしか最適化できない。たとえば、GCCの-ffast-mathだ。

c - Why doesn't GCC optimize a*a*a*a*a*a to (a*a*a)*(a*a*a)? - Stack Overflow

GCCに-ffast-mathオプションを指定すると、浮動小数点数演算の誤差を気にしないとコンパイラーに伝えたことになる。このオプションを指定すると、GCCは浮動小数点数の演算に対して、大胆な最適化ができるようになる。もちろん、演算精度に注意しなければならない。

What Every Computer Scientist Should Know About Floating-Point Arithmetic(すべてのコンピューター科学者が浮動小数点数演算について知っておくべきこと)

ドワンゴ広告

この記事はC++とは直接関係がないが、ドワンゴ勤務中に書かれた。

ドワンゴはIEEE 754フォーマットを忘れたくても忘れられない本物のプログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-03-27

2014-02-post-Issaquahのレビュー: N3910-N3919

引き続き、2014-02-post-Issaquahの論文集を解説していく。

N3910: What can signal handlers do? (CWG 1441)

シグナルハンドラーの中で、アトミック変数を使えるように文面を変更した所、うっかりと、volatileでもatomicでもない変数が使えないように解釈できる分綿と鳴ってしまった。この文面を修正するにあたって、そもそも、既存の文面を厳密に解釈した所、色々と本来意図しない制限があることが判明した。その制限を緩和する提案。

この文面変更は、もう少し継続した議論が必要だということで、C++14には入らない。

シグナルハンドラーはロックフリーなアトミック操作を行うことができる。

[PDFにする必要が感じられないPDF] N3911: TransformationTrait Alias void_t

エイリアステンプレート、void_tの提案

void_tのリファレンス実装は以下の通り。

// N3911提案のvoid_tのリファレンス実装
template < typename ... >
using void_t = void ;

これだけである。「ハァ? なんだそりゃ」と読者が思うのも無理はない。しかし、これだけなのだ。

なんでこんな単純極まりないものを、標準ライブラリに入れなければならないのか。それは、この一件単純すぎるエイリアステンプレートが、テンプレートメタプログラミングでとても重宝するからだ。

たとえば、ある型が、ネストされた型名typeを持つかどうか調べる、メタ関数を書いてみよう。

// has_typeの実装
template < typename ... >
using void_t = void ;

template < typename, typename = void >
struct has_type
    : std::false_type { } ;

template < typename T >
struct has_type< T, void_t< typename T::type > >
    : std::true_type { } ;

void_tは、任意個の型を受取、かならずvoidを返すので、とても使いやすい。いくらでも型を突っ込むことができる。そして、突っ込んだ型がすべてwell-formedならば、void_t自体もwell-formedになる。ひとつでもill-formedな型がまじっていれば、void_t自体もill-formedとなる。これはつまり、SFINAEのために悪用可能である。

さて、実はこの単純極まりないvoid_tエイリアステンプレートではあるが、ひとつ問題が持ち上がっている。なんと、GCCとClangの間で、実装上の差異があるのだという。なぜそんな自体に陥ったかというと、規格の文面の問題である。なんと、エイリアステンプレートの未使用のテンプレート実引数の扱いをどうするか、規格上、まったく規定していなかったのだという。

この問題は、core issue 1558で把握されていて、現在の議論による解決案は、未使用のテンプレート実引数であっても、SFINAEで考慮されるようになる方向で、変更されるように調整が進んでいる。したがって、この論文の利用方法に合致する。

論文では、当面のworkaroundとして、未使用のテンプレート実引数を出さない、以下のようなマヌケな実装を提示している。

// 当面のマヌケなworkaround
template< class... > struct voider { using type = void; };
template< class... T0toN > using void_t = typename voider<T0toN...>::type;

N3912: Auto and braced-init-lists, continued

これは小さいが下位互換性をぶち壊す提案。

C++11では、braced-init-listをauto指定子でうけると、型はinitializer_listになる。

// C++11のコード
auto x{ 0 } ;       // std::initializer_list<int>
auto x{ 0, 1 } ;    // std::initializer_list<int>
auto x = { 0 } ;    // std::initializer_list<int>
auto x = { 0, 1 } ; // std::initializer_list<int>

新しいlambdaキャプチャーの文法である、init-captureは、autoと同じ方法で型推定を行うので、これは問題になる。

// C++11の型推定ルールを使ったinit-capture
[ x{0} ] (){} ;         // std::initializer_list<int>
[ x{0, 1} ] (){} ;      // std::initializer_list<int>
[ x = {0} ] (){} ;      // std::initializer_list<int>
[ x = {0, 1} ] (){} ;   // std::initializer_list<int>

これはさすがに問題がある。

このため、N3912は、なんと直接初期化の場合、initializer_listとはならない変更を提案している。

// N3912提案
auto x{ 0 } ;       // int
auto x{ 0, 1 } ;    // ill-formed
auto x = { 0 } ;    // std::initializer_list<int>
auto x = { 0, 1 } ; // std::initializer_list<int>

同様に、init-captureも以下のようになる

// N3912提案のinit-capture
[ x{0} ] (){} ;         // int
[ x{0, 1} ] (){} ;      // ill-formed
[ x = {0} ] (){} ;      // std::initializer_list<int>
[ x = {0, 1} ] (){} ;   // std::initializer_list<int>

これは、もちろん下位互換性をぶち壊す。しかし、Issaquah会議での投票により、この変更は好ましいとされた。

この変更が、この最終段階で、C++14に入るかどうかは、未定である。ひょっとしたら入るかもしれないし、次に持ち越されるかも知れない。

これは興味深い変更だ。下位互換性をぶち壊すという点がとても興味深い。

これはもともと、シカゴ会議のときにフィンランドのNBコメントとして出ていて、その時には却下されているが、今回、init-captureという新たな問題が持ち上がったことにより、問題が再認識され、議論が再開された。

[古典的に悲惨なPDF] N3913: Greatest Common Divisor and Least Common Multiple, v2

最大公約数と最小公倍数を計算する関数テンプレート、gcdとlcmを<numeric>に追加する提案。

前回の論文、[PDF注意] N3845では、<cstdlib>に提案されていたが、議論の結果、合意が得られずに、ヘッダーが変更された。

N3914: Additional Core Language Issue Resolutions for Issaquah

コア言語のちょっとした文面上の解釈揺れなどを修正する提案。

N3915: apply() call a function with arguments from a tuple (V3)

tupleの全要素を関数オブジェクトの実引数に渡してくれるヘルパー関数テンプレート、applyの提案。

前回の論文、[PDF注意] N3829からは、ほとんど変更はない。

[PDFという多様性はいらない] N3916: Polymorphic Memory Resources - r2

この提案論文は、アロケーターに実行時ポリモーフィズムを実現するための、Polymorphic Memory Resourcesの提案である。

従来のC++のSTLでは、アロケーターは、テンプレート実引数で指定する。たとえば、独自実装のアロケーターを使いたい場合、以下のように書く。

// アロケーターを指定する例
#include <memory>
#include <string>

// 独自実装のアロケーター
class super_fast_allocator ; 
class awesome_allocator ;


int main()
{
    std::basic_string< char, std::char_traits<char>, super_fast_allocator > s1 ;    
    std::basic_string< char, std::char_traits<char>, awesome_allocator > s2 ;
}

なるほど、これは動く。しかし、色々と問題がある。まず、s1とs2は、別の型になってしまう。s1とs2の違いは、その生のストレージがどのように確保されるかという違いだけで、その他は同じであるはずだ。それにも関わらず、型が異なってしまう。

それに、このコードは、コンパイル時にアロケーターを指定子なければならない。しかし、多くの現実のプログラムは、実行時にメモリ確保の戦略を変えたいはずだし、メモリ確保の戦略を変えるためだけに、わざわざコンパイルし直すことはない。

この問題は、古典的なオブジェクト指向で解決できる。すなわち、抽象基本クラスを指定して、そこから派生して具体的な実装をし、基本クラスへのポインターを経由して、virtual関数を呼び出すのだ。問題は、そのためのアロケーターの基本クラスを、標準ライブラリは定狂していない。そのため、これを実現しようとすると、利用者がそれぞれ独自に基本クラスを定義しなければならなくなる。他人の書いたコードを混在させるのが難しくなる。

そもそも、メモリ確保の戦略をコンパイル時に決定できない状況で、わざわざアロケーターをテンプレート化する意味があるだろうか。コンパイル時に指定する必要のないもの、コンパイル時に汎用化できないものを、テンプレートにする意義は薄い。

このため、N3916は、実行時ポリモーフィズムを実現するためのクラス、memory_resourceと、それを従来のアロケーターにするためのラッパークラス、polymorphic_allocatorを提供している。さらに、それ以上にも色々と提供している。

注意:以下の解説は、まだ提案段階の論文、N3916を元に解説している。この提案のあらゆる内容は変わる可能性がある。

std::pmr名前空間

Polymorphic Memory Resourceのライブラリは、std::pmr名前空間スコープに配置される。pmr名前空間は、仮の名前で、いずれバイク小屋議論を巻き起こすであろう。

memory_resource

memory_resourceとは、抽象基本クラスで、バイト単位の生のストレージの確保、解放をするためのクラスである。このクラスには、allocate, deallocate, is_equalというメンバー関数があり、それぞれdo_allocate, do_deallocate, do_is_equalというpure virtual functionを呼び出す。

// memory_resourceの実装例
namespace std { namespace pmr {

class memory_resource
{
private :
    static constexpr std::size_t max_align = alignof(maxalign_t) ;

public :

    virtual ~memory_resource() { }
    void * allocate( size_t bytes, size_t alignment = max_align )
    { return do_allocate( bytes, alignment ) ; }
    void  deallocate( void * p, size_t bytes, size_t alignment = max_align )
    { do_deallocate( p, bytes, alignment ) ; }

    bool is_equal( const memory_resource & other ) const noexcept
    { do_is_equal( other ) ; }

protected :

    virtual void * do_allocate( size_t bytes, size_t alignment ) = 0 ;
    virtual void do_deallocate( void * p, size_t, bytes, size_t alignment ) = 0 ;
    virtual bool do_is_equal( const memory_resource & other ) const noexcept = 0 ;
} ;

} }

独自のメモリ確保を実装する際には、このmemory_resourceから派生して、do_xxxをオーバーライドする。

// 独自のストレージ確保クラスを実装するひな形
class super_fast_mr
    : memory_resource
{
protected :
    virtual void * do_allocate( std::size_t bytes, std::size_t alignment )
    {
        // サイズが少なくともbytes、でアライメント要求がalignmentを満たすストレージを確保して、そのストレージへのポインターを返す
    }

    virtual void * do_deallocate( void * p, std::size_t, bytes, std::size_t alignment )
    {
        // ストレージを解放
    }

    virtual bool do_is_equal ( const memory_resource & other ) const noexcept
    {
        // *thisとotherを比較
    }
} ;

polymorphic_allocator<T>

polymorphic_allocatorは、memory_resourceをラップして、std::allocatorと同等のインターフェースを提供するクラステンプレートである。std::allocatorのかわりに、共通の基本クラスとして使うことができる。

// 例
class custom_resource : std::pmr::memory_resource
{ /* 実装 */ } ;

int main()
{
    custom_resource cr ;
    using vec = std::vector< int, std::pmr::polymorphic_allocator<int> > ;
    vec v( std::pmr::polymorphic_allocator<int>( &cr ) ) ;
}

ただし、いちいちアロケーターを指定するのは面倒だ。そのため、標準ライブラリで、エイリアステンプレートが用意されている。

// エイリアステンプレートが提供される
namespace std { namespace pmr {

template < typename T >
using vector = std::vecotr< T, polymorphic_allocator<T> > ;

// ... その他のコンテナー
} }

resource_adaptor<Alloc>

resource_adaptorは、従来のアロケーターをmemory_resourceのインターフェースに合わせるラッパークラステンプレートだ。

// 従来のアロケーター
class custom_allocator { /* ... */ }

int main()
{
    using custom_resource = resource_adaptor< custom_allocator > ;
}

その他

new_delete_resource関数は、allocateやdeallocateがグローバルなoperator new, operator deleteを呼び出すmemory resourceへのポインターを返す。

null_memory_resourceは、allocateが必ず失敗してbad_alloc例外を投げるmemory resourceへのポインターを返す。このポインターは、memory resourceの集合の最後に番兵として配置するのに使うことができる。また、テストのために使うこともできる。

get_default_resourceは、プログラムでデフォルトのmemory resourceへのポインターを返す。set_default_resourceは、デフォルトのmemory resourceへのポインターをセットする。

標準のmemory resource

論文では、二種類(細かく分けて三種類)の標準で提供されるmemory resource実装を提案している。

synchronized_pool_resource/unsyncronized_pool_resource

この二つのクラスは、確保したストレージを所有していて、デストラクターで一括して開放する。つまり、確保したストレージ片を個別に開放しなくても、このオブジェクトの破棄とともに、一括解放されるのだ。

// synchronized_pool_resourceの例
int main()
{
    {
        synchronized_pool_resource spr ;
        spr.allocate( 100 ) ;
        spr.allocate( 100 ) ;
        spr.allocate( 100 ) ;
    } // 一括解放される

}

deallocateしなくても、synchronized_pool_resourceが破棄されるときに、そのオブジェクトから確保したメモリは、すべて解放される。

unsynchronized_pool_resourceは、マルチスレッドから同時にアクセスして動くことが保証されていない。そのため、実装に酔っては、スレッド間の同期処理を省くなどして、より効率的な実装とすることを許している。

実装例としては、メモリをチャンクと呼ばれる一定サイズごとに区切って、別々のチャンクごとの専用ヒープから確保するような方法が考えられる。

pool_optionsで、色々と設定もできるようになっている。

monotonic_buffer_resource

これはかなり特殊なメモリ確保戦略を取る。このクラスのdeallocateメンバー関数は、何もしない。このクラスを用いて確保したメモリーを、個別に解放することはできない。確保したストレージは、クラスのオブジェクトに所有され、オブジェクトが破棄されるときに、一括して破棄される。

このmemory resourceは、すぐに一括して破棄する小さなオブジェクト群のためのストレージを高速に確保するのに向いている。

また、polymorphic memory resourceは、これまでstd::functionやstd::promiseが、実装上必要になっていた、アロケーターのtype erasureの実装を、標準化するという意味合いもある。polymorphic memory resourceが採択されれば、std::functionやstd::promiseは、polymorhpic memory resourceを使うと規定されるようになる。

N3918: Core Issue 1299: Temporary objects vs temporary expressions

temporary object(一時オブジェクト)という用語があり、temporary expression(一時式)という用語もある。ところで、exception object(例外オブジェクト)は、もはやtemporaryとは何の関係もない。しかし、現行規格の文面上、関係のあるようになってしまっている。このために、文面を修正して、明確に分離する提案。

[C++論文フォーマットとしてPDFはサポートしなくてよい] N3919: Transactional Memory Support for C++

[PDF注意] N3859の改訂版。どうもあまり違いが見られないようだが。

Transactional Memoryの詳しい解説については、本の虫: 2014-01-pre-Issaquah mailingの簡易レビュー Part 1を参照。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-03-25

2014-02-post-Issaquahのレビュー: N3900-3909

2014-02-post-Issaquah mailingsが公開された。

最新のドラフトは、N3936となった。

[一発目から気分の悪いPDF] N3900: WG21 2014-01-31 Telecon Minutes

2014年1月31日に行われた電話会議の議事録。

[二発目にも気分を害するPDF] N3901: Minutes (February 2014) WG21 Meeting No. 57 N3902: Minutes (February 2014) PL22.16 Meeting No. 62

2014年2月15日に、米国ワシントン州Issaquahで開かれた国際会議の議事録。

N3903: C++ FCD Comment Status

FCDに対するNBコメントへの返答一覧。

スイス(・∀・)< C++14はバグ修正リリースとマイナー新機能のはずだろ。標準規格の品質を下げる新機能を全部外せ。互換性をぶち壊す変更をいれんな。

(´・ω・`)< すまんかった。std::dynarrayとstd::optionalはドラフトから外すわ。

ああ、ああああ。std::optionalが消えてしまう。なんということだ。スイスのせいで・・・スイスのせいで・・・

一方、std::dynarrayは、スタックからネストされた確保という概念に、もう少し議論が必要なので、外すのは妥当である。

このように、国家を代表するNBコメントは、とても強い力を持っている。日本のC++WG JPがNBコメントを送れる状況ではないのは、残念でならない。

イギリスからのNBコメントである、「u8"À"はu8"\u00c8"となり、これをUTF-8エンコードすると、char[3]が、{ 0xc3, 0x80, 0 }と初期化されることになる。しかし、charは0x80を表現可能であると保証されていない」というコメントに対しては、UTF-8のオブジェクト表現は、それぞれUTF-8エンコードのコードユニットの値をもち、0から255までの値は、charとunsigned charで、相互に変換可能な表現方法が存在するという規程が設けられることになった。

最初からUTF-8文字型として、char8_tを規定していればよかったのに。

1759を参照。

また、C++14では、連続したメモリ確保を、一括したメモリ確保に変えることを、実装に許す制限緩和が入った。問題は、そのような制限緩和を行った結果、従来は小さなメモリーリークだったコードが、大きなメモリーリークに変化してしまう可能性がある。

// 大きなメモリーリークになってしまう例
class P {
  int x;
};
class Q {
public:
   Q(){ throw 42; }
private:
   int x[LARGE_NUMBER];
};
{
   P* p1 = new P();
   Q* q1 = new Q(); // bang :-(
   // don't get here
   delete q1;
   delete p1;
}

このコードは、bangの時点で、例外が投げられる。C++11までのように、すべてのnew式で、独立してメモリ確保がされるのであれば、Qで確保されたメモリは、オブジェクトの構築中に例外が投げられたことにより解放されるはずである。しかし、もしPとQのメモリ確保がまとめられるのであれば、Qを構築する部分のメモリもPと一緒に確保されてくっついているので、そのままリークしてしまう。

もちろん、このコードは、もともと間違いであるが、小さなメモリーリークを大きなメモリーリークにしてしまう変更はいかがなものか。そのため、そのような場合に対応するために、何やら変な条件が付け加えられた。

1786を参照。

[title要素のないHTML] N3905: Extending std::search to use Additional Searching Algorithms (Version 4)

現在、STLのアルゴリズムには、std::searchがある。しかし、検索アルゴリズムというのは、ひとつではない。特殊な文脈では、もっと効率的にうごく検索アルゴリズムがある。たとえば、Boyer-Mooreが有名だ。

一般に、これらの検索アルゴリズムは、検索を行う前に、検索準備のためのパターン構築処理を行う。この前処理にはコストがかかるが、検索をかける現実のデータには、たいてい偏ったパターンが存在するので、うまくはまれば検索を高速ができる可能性があり、前処理のコストを考えても、通常の愚直な検索にくらべてお釣りがくることもあるのである。

この論文では、このような検索アルゴリズムを、汎用的にサポートするために、std::searchに新しいオーバーロードを追加することを提案している。新しいオーバーロードされたsearchは、Search Objectという追加の実引数を取る。これは、検索に使われる前処理された結果生成される、何らかのオブジェクトだ。検索する際には、そのオブジェクトを使って検索を行う。

論文では、デフォルトの追加検索アルゴリズムとして、Boyer-Mooreと、その改良版であるBoyer-Moore-Horspool(オリジナルよりメモリ使用量が低いが、worst-caseパフォーマンスでオリジナルに劣る)を追加する提案をしている。

// N3905提案の例

// 従来の検索
auto iter = std::search( corpus_first, corpus_last, pattern_first, pattern_last ) ;

// 従来のコードの新しいインターフェース版
auto iter = std::search( corpus_first, corpus_last, std::make_default_searcher( pattern_first, pattern_last ) ) ;

// Boyer-Mooreによる検索
auto iter = std::search( corpus_first, corpus_last, std::make_boyer_moore_searcher( pattern_first, pattern_last ) ) ;

Boyer-MooreとBoyer-Moore-Horspoolは、比較関数とハッシュ関数の両方を必要とする。

論文筆者によるリファレンス実装が、GitHubに上がっている。

mclow/search-library

[PDF警告] N3906: ISO/IEC PDTS 18822, File System, National Body Comments

Filesystemライブラリに対するNBコメント集。回答は次の会議の後以降になるだろう。

N3908: C++ Extensions for Library Fundamentals, Working Draft

標準ライブラリのTS(Technical Specification)のドラフト。TSは正式な規格とは分離される。C++に対する実験的な拡張案を、すこし正式に提案する程度の位置づけという感じだ。これはC++標準規格とは別物で、実際にC++の正式な規格に入るわけではない。

[江添フレンドリーではないPDF] N3909: A SFINAE-Friendly std::iterator_traits, v2

iterator_traitsをSFINAEフレンドリーにする提案。

SFINAEフレンドリーの解説については、本の虫: 2014-01-pre-Issaquah mailingの簡易レビュー Part 1を参照。

ドワンゴ広告

近況:社内IRCで、":q!"、と誤爆した人がいたが、幸い宗教戦争には発展しなかった。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-03-24

ドワンゴの女子マネという過酷な訓練

ドワンゴ現在、ドワンゴでは「女子マネ弁当」という企画が復活している。

過去の女子マネ弁当の様子については、すでに社外にも相当の情報が出回っているので、例えば以下のような情報を参考にしてもらいたい。

【第1回】ドワンゴ大改革の鍵は、インフラと女子マネージャー。|川上量生の胸のうち|川上量生|cakes(ケイクス) ドワンゴ「助けて! エンジニアが朝出社しないの!」→ 女子マネージャーが弁当を手渡してくれる「女子マネ弁当」システム導入で生活習慣改善へ - ねとらぼ

今回は、その女子マネ弁当の実情に迫る、社内からのレポートをお届けする。

女子マネ弁当の概要とは以下の通りである。

  • 3月17日から、4月25日までの一ヶ月間、午前10時30分までに出社すると、以下の特典がある
  • 午前10時30分から、エンジ色のジャージを来た女子マネ人員(なぜか若い女性のみで構成されている男女比率の偏った集団)が、エンジニアのいるフロアにやってきてラジオ体操をする
  • ラジオ体操をしたのならば、女子マネにスタンプを押してもらう
  • 当日のスタンプの押された用紙を持っていれば、午前11時45分から午後1時15分までの間に、社内カフェテリア(通称リフレ)で、またもや女子マネから、無料の弁当をもらえるし、社内タリーズで当日に限り700円分の買い物が無料でできる。

さて、その実態はどうか。

  • 午前10時頃、女子マネ人員は、エンジニアが極限の集中力を発揮して仕事をしている神聖なフロアにやってきて、ペチャラクチャラとやかましくたわいもない私語をしている。集中力が乱されることこの上ない。このため、本当に集中して仕事をしたいエンジニアは、自分のデスクを捨てて別のフロアに避難している。
  • 午前10時20分頃、手際悪くラジオ体操の音楽をスピーカーから流すテストが行われる(なんどか失敗する)
  • 午前10時30分、ラジオ体操が始まる。女子マネはド素人丸出しのへにゃへにゃな動きでラジオ体操の見本展示をする。
  • 体操後、一人ひとりスタンプカードを持って並び、女子マネに当日のスタンプを押してもらう。これは極めて効率が悪く、時間のかかる作業である。
  • 午前11時頃、ようやく悪夢が去り、エンジニアのフロアは静寂を取り戻す。
  • 午前11時45分から、無料の弁当を求めてドワンゴ社員が殺到するため、リフレが混雑する。このために、昼飯を食べながらリフレでカタンをするという極めて重要な昼の恒例行事が行えない。

謎だ。なぜこんなクソな企画が平然と行われているのか。なぜエンジニアは不満の声を挙げないのか。なぜこんな肥溜めのようなクソに耐えているのか。

どうやら、ドワンゴのエンジニアにとっては、無料の食事はとてつもないほど魅力的らしい。そのために、このようなクソの嵐にも耐えているようだ。

曰く、「無料の食事は素晴らしい」、曰く、「運動不足だけどきっかけがないと運動できない。皆で一斉に行うラジオ体操があれば参加したい」、曰く、「どうせ朝出てこないので関係ない」

しかし、筆者は未だに、エンジニアから、「女子マネは必要だ」という意見を聞いたことがない。体操の見本展示は、体操のプロが行うべきであって、単に若い女であるからという理由だけで集められたド素人に任せる仕事ではない。男女雇用機会均等法の観点からも怪しい。エンジニアが女子マネに反対しない理由は、女子マネ企画に付随する副産物が素晴らしいのであって、女子マネはエンジニアからは望まれていないのだ。

いったいこれは何なのだ。ムチとアメを両方与えているようなものだ。そのアメがあまりにも甘美なために、あえてムチに耐えているだけだ。

だいたい、この上から与えられる娯楽というのは、まったくエンジニアの精神にそぐわない。もし、本物のエンジニアが娯楽が欲しいと思ったら、自分で娯楽を作り出すべきなのだ。上から与えられる娯楽を享受しているだけでは、本物のエンジニアたりえない。

しかし、ここで筆者はあることに気がついた。女子マネが存在しても、別に開発効率は落ちていない様子である。

考えてみれば、午前10時というのは、ドワンゴ感覚で言えば、社外ならば午前5時頃に匹敵する早朝だ。そんな時間に出勤できるエンジニアはまれである。ドワンゴでは、朝といえば午後1時か2時、昼といえば、午後5時か6時ごろなのだ。もし、ドワンゴ社員が、午前10時に社内にいたということは、彼は昨日の夜から社内にいたと考えるべきである。

さらに、筆者がC++WG論文をレビューする速度も、女子マネが始まってから上がっている。なぜならば、リフレが混雑して昼ボドゲができないために、論文を読む時間が増えるのだ。

そうか。そうだったのか。女子マネという一件クソな企画は、エンジニアの効率を上げるための企画だったのだ。エンジニアに規律をもたらす企画だったのだ。

なるほど、それで合点が行くことがたくさんある。いままで、ドワンゴ社内で、なぜこんなにクソなのか理解に苦しむ部分が、多数あったのだ。

たとえば、ドワンゴ社員に支給される作業用のPCは、基本的に、メモリをたったの8GBしか積んでいないクソみたいなスペックのラップトップ一台である。このラップトップは非力すぎて、いまどき仮想環境を一個立ち上げるのにも不満を感じるほどである。これは、そのような非力なコンピューター上でも快適に動作するソフトウェアは、他の環境でも快適に動作するだろうという訓練の一環だったのだ。

支給されるディスプレイは、FULL HDですらない低解像度のディスプレイで、粗悪なパネルを使っていると見えて視野角が非常に狭く、画面全体が小便でガラスを作ったのかと思われるほど黄色い色合いのクソみたいなディスプレイである。いまどき、IPSパネルのディスプレイなど安いはずであるが、あえてこのような尿パネルのディスプレイを使っているのは、画面全体を適当に眺めるのではなく、一字一字、顔面を肉薄させて、しっかりと確認をさせるための訓練であろう。

社内ではEXCEL方眼紙が飛び交っている。これは、エンジニアに一般ピーポーの感覚を植え付けるためであろう。

社内システムのうち、建て替え経費精算システムは、不自由なWindows上で動作する32bit版IE6/7/8でしか動作しない。その理由は、ブラウザーから直接印刷をするために忌まわしきActiveXを使っているからだ。もちろん、そんな超古代の化石のような環境を手元で用意できるわけがない。そのため、リモートデスクトップ接続できる、大昔のIEが動く環境を特別に用意して、建て替え経費精算システムを使う際には、その環境にログインして、そこから行うようになっている。これは、不正な経費申請を防ぐために、わざと使いづらくしているのであろう。

社内には汚らしいニコチン中毒者のために、ガラス張りの大きな喫煙所が設置されている。これは、動物園で檻の中に入ったサルを見学するのと同じものに違いない。麻薬は人をダメにする反面教師としてである。

昔の社屋にはあった昼寝部屋は、今の歌舞伎座タワーに移転してからはなくなった。いまでは、身長160cmの筆者ですらはみ出してしまう、極めて寝心地の悪い狭いソファーがたったの3個、置いてあるだけである。広い喫煙所に比べて、なんと貧相なことか。これは、昼寝ばかりしていないで仕事をしろということだろう。

机も狭くなった。昔は120cmぐらいの奥行きがあり、広さは足元にPCケースが2,3台はおけるほどであり、しかもL字型であったと聞いているが、いまではそっけない机がひとつあるだけだ。これも、空間を効率良く使えという訓練のためだろう。

規律と、貧弱な環境に耐えて作業をさせたいのならば、なぜ裁量労働制を採用しているのか。なぜ昼寝をしている人間を叱らないのか。その理由は、上からの押し付けでは人は変わらないためである。自らその価値に気づかねばならない。徐々にその価値に気づかせる措置が、この一見クソに見える現状なのだろう。

この女子マネ弁当に隠された真の意図に気がついた筆者は、今日は大真面目にラジオ体操を行った。みずから皆の前に立ち、ラジオ体操の見本展示を行った。これから毎日、積極的にラジオ体操に参加することとしよう。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

ドワンゴは、わざと集中力を乱される環境でも、非力なコンピューター環境でも、集中して仕事ができる本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-03-22

SPAMは意外とうまい

妖怪ハウスにSPAMが送られてきたので、ゴーヤチャンプルとSPAM MUSUBI(SPAMを挟んだ海苔巻き)を料理した。

うまい。これはうまい。SPAMがすでに塩分が多いということで、塩を使わなかったのだが、この塩味がちょうどいい。

なんと、筆者は今まで、SPAMの価値をバカにしていた。はるかに多い目方の肉が、より安く変えるこの日本で、SPAMというのは無用の長物だと思っていた。あんなものは味のわからないイギリス人とアメリカ人の食べ物だとばかり思っていた。しかし、この塩味は米とよく合う。

そしてゴーヤだ。筆者は今までゴーヤを食べたことは一度もなかった。ゴーヤというのは、見るからに固そうで、どう料理していいかわからず、買うのを避けてきた。今回、ゴーヤチャンプルを作るために買ったのだが、これがうまい。苦くてうまい。薄切りにして炒めると実にうまい。

そして、SPAMとチーズとアボガドを挟んだ海苔巻きも、実にうまかった。

しかも、SPAM缶はまだ7缶も残っている。SPAM缶は保存が聞く。

スパム、スパム、スパム ラブリースパーム! ワンダフルスパーム! ラブリースパーム! ワンダフルスパーム!

spamが送られてきた

最近の怒涛のようなAmazon.co.jp: 江添亮: 江添のほしい物リスト経由の贈り物もようやく止まり、平穏な暮らしを享受していた今日このごろに、静けさを破って突如やってきたお届け物がひとつ。品名をみると、「減塩スパムランチョミート」と書かれている。

はて、スパム・・・スパム、スパム、ラブリースパーム! ワンダフルスパーム! ラブリースパーム! ワンダフルスパーム!

いかん、バイキングになりかけてしまった。気を取り直して改めてよく観察すると、なんと、沖縄県から送られてきている。本格的だ。

妖怪ハウスには天然のスパムフィルターが常備されており、たまに郵便物が届かないことがある。実際、アマゾンの欲しい物リストで購入済みになっているものが何点か、まだ届いていない。それが、届いていればいいブログのネタになったであろう商品だけに、実に惜しいのだ。

逆に、妖怪ハウス宛ではないのに届いてしまうこともよくある、住所が違っているのに届けられることも珍しくないので、その都度連絡して引き取りに来てもらっている。どうも野方の郵便局や配達業者は、誤配が多い気がする。前に裁判所からの書類が届かなかった例があったそうで、極めて危険なものを感じる。

それはさておき、天然のスパムフィルターを通過してやってきたこのスパム、いったいどう料理してくれようか。

スパムのことは、すぐに記事を書こうと思っていたのだが、あいにくと体調を崩してしまい、今週の後半はブログを書けなかった。病の床に臥せっている時に、もうひとつの小包が届いた。みると、またスパムらしい。

なかには、減塩スパムとガーリックスパムの缶が入っていた。

そして、何やら直方体の箱がひとつ。SPAM™ "MUSUBI"と書いてある。どうやらこれは、スパム・ムスビなる料理を作るための器具らしい。開けてみると、透明なプラスチックの容器と、小型のSPAM缶が入っていた。またSPAMか。

箱の裏側には、"How to make SPAM™ Musubi" と写真付きのスパム・ムスビ作成方法の解説が載っていた。スパム・ムスビとはかっこいいが、単にスパムを挟んだ四角形の海苔巻きだ。なぜスパム・ノリマキという名前ではないのだろうか。

スパム、スパム、スパム、スパム・・・

シャッタープ!

さて、スパムの料理方法だが、このスパム・ムスビという名前の海苔巻きの他には、どうしようか。同居人によれば、ゴーヤ・チャンプルをおすすめされた。ゴーヤを買ってきて料理することとしよう。妖怪ハウスに来た折には、スパムを振る舞うことができるようになったわけだ。

実に、必要に迫られたために、筆者の料理の腕前がめきめき上がりつつある。5kgのスパゲティを手に入れたので、この際にホワイトソースとトマトソースの作り方を会得した。今日明日中に、ミートソースの作り方も会得する予定だ。

さて、またもや本の虫著者の大勝利であります。ブログ著者の戦略はいつも同じ。ブログでネット乞食をしてまんまと物をせしめる。せしめたものはネタとしてためておいて、ブログに駄文を書く。ブログを書いたならば、妖怪ハウスでスパム美味しくスパム料理してスパム食べスパム、スパム、スパム、ラブリースパーム! ワンダフルスパーム!

2014-03-21

妖怪ハウスの電源事情

妖怪ハウスは今、電源問題をかかえている。ブレーカーが落ちるという問題だ。

妖怪ハウスは5LDKの住居で、どうやら区画ごとに20Aのブレーカーが設置されているようだ。

妖怪ハウスのリビングは、住人の集まる共用スペースとなっている。ここには妖怪ハウスの住人が憩うための電化製品が満載されていて、かなりの電力を消費する。

まず、照明が電力を食う。調光機能付きの電球ソケットなので、レフランプか、調光機能に対応した一個5千円以上するとてつもなく高いLEDしか取り付けられない。現在、90Wのレフランプを6個取り付けている。

そして、冬の時期はコタツが設置されている。

もちろん、大型のテレビもあるし、飲み物や食べ物を保管するための冷蔵庫も設置されている。

もちろん、住人はそれぞれにコンピューターを持ち寄って作業する。

そして、レンジまである。このレンジが曲者で、ブレーカーを落とす最後の引き金を引くのは、たいていこのレンジだ。人が集まって電力消費が高くなったところで、誰かがものを温めようとレンジを使い、ブレーカーが落ちるというのがよくあるパターンだ。とりあえず、このレンジは一時的に撤去した。

クーラーも備え付けのものが壁に埋め込まれているのだが、この電源のブレーカーは、ひょっとしたら独立しているのかもしれない。

とにかく、クーラーを無視しても、リビングは電力を消費するのだ。20Aを超えることは、さほど難しくはない。

昨日も、リビングのブレーカーを落としてしまった。原因は分かっている。照明とコタツとホットプレートを使用中に、レンジまで使おうとしたのだ。

ブレーカーが落ちたのならば、戻せばいい。そして、電気が使い過ぎなことが判明するので、後から気をつければいい。そうすれば電気代も安くすむはずである。妖怪ハウス全体の契約アンペアはもっと高いし、ブレーカーが細かく分けられているのであれば、他の場所には影響は及ばない。何が悪いのか。

妖怪ネットワークである。

妖怪ネットワーク、すなわち筆者の構築した妖怪ハウスのネットワーク環境を支えるネットワーク機器は、配線の都合上、リビングに設置されている。つまり、リビングで停電が起きると、全部まとめても消費電力はたったの数十ワットほどのネットワーク機器が、根こそぎ停止してしまう。妖怪ネットワークが死んでしまうのみならず、ネットワーク機器にもよろしくない。

短期的には、他の停電が起こりそうのない、独立したブレーカーの配電された場所から電源を引っ張ってくるworkaroundが考えられる。

問題は、リビングから直接つながっている隣の和室も、ブレーカーの配電としては同じになっているらしく、リビングの停電の巻き添えを食ってしまうのだ。

思うに、キッチンなら停電は少ないはずだ。キッチンには、照明の他には、壁に埋め込まれた電気式のレンジ兼オーブンと、電気ケトルや炊飯器がある程度だ。消費電力の高い機器はあるものの、20Aのブレーカーが落ちるほどの電力消費の集中はしないはずだ。ネットワーク機器にはキッチンから電力を供給しよう。

ネットワーク機器というのは、全部まとめても数十ワット程度なのだから、長期的にはUPSを導入するべきだろう。やれやれ、また出費が大きい。ただ、UPSは一度使ってみたかった機器なので、この機械に触ってみるのもいいだろう。

2014-03-18

みずほ銀行の信じられない契約軽視姿勢

仕事のため、みずほ銀行の個人の口座を作る必要があったのだが、その銀行口座を解説する手続きで、対応にあたった行員が、極めて信じられないほどに契約というものを軽視していた。

みずほ銀行に口座を開く手続きのために、書類に必要な事項を記載し、署名捺印となった。行員は捺印の二箇所を私に指示した。一箇所は単に捺印するだけであったが(法的にも、印鑑は署名の代わりに補助的に用いることができるだけの極東の奇妙な風習である)、もう一箇所には、「私は規約に同意しました」的な文面があった。

はて、これはなんだろう。

私「すみません、これはなんですか」
行員「そこに押してください」
私「いえ、この規約ですが、これはどこにあるのですか」
行員「それでしたら裏にあります」

なるほど、裏にかかれていた。その規約を確認すると、みずほ銀行は私の個人情報を、市場調査などの統計解析のために使うことができるし、ダイレクトメールを送りつけるためにも使うことができると書かれていた。

私「市場調査のための統計解析に私の個人情報を使うのですか?」
行員「はい。それは市場調査のために使う可能性があるということです」
私「ダイレクトメールを送るために私の個人情報を使うのですか?」
行員「いえ、それは、クレジットカード会社が宣伝のためにダイレクトメールを送る可能性があるということです」
私「しかし、この文面によれば、クレジットカード会社に限るようには読めませんが」
行員「えーと、ちょっとすみません」
(行員、規約の文面を確認する)
行員「そのようですね」

何だこの素人ぶりは? 可能性? なぜ人に契約するよう指示する文面について理解していないのだ。

さらに確認すると、その他の規約については、別のもの(文書名を失念)を参照している。なるほど、するとその参照されている[文書名]の規約にも同意したことになるわけだ。

私「この[文書名]はどこで閲覧できますか?」
行員「それは契約後に自宅に送る資料に含まれています」
私「今確認できないのですか?」
行員「あとで自宅に送ります」
私「あなたは、今ここで私が確認できない契約への同意を私に求めているのですか?」
行員「あとで手元に資料が届いて、確認した後に解約できます」

いったい何なんだ。この契約の軽さは。みずほ銀行というのはこんなにも契約を軽んじている銀行なのか。

私「そもそも、あなたははんこを押すことを私に指示する前に、この規約を私に読ませるべきだったのではないですか」
行員「そうでした。すみません」

行員は何の感情も示さずに、慌てず騒がず、プロフェッショナルに謝罪した。まるで機械のような即答ぶりだった。不思議だ。ここは本来、大慌てするべきところではないのか。この行員は、契約締結にあたって、私に契約内容を一切説明しなかったのだ。そのような契約の有効性は疑わしいものだ。

仕事で必要なので、私は仕方なくみずほ銀行の口座を作った。しかし、みずほ銀行のこの契約に対する軽さはなんなのだろう。みずほ銀行員は契約の文面を契約予定者に確認させずに、契約予定者に署名捺印を指示した。これは単に行員個人の問題ではなく、みずほ銀行全体の問題のように思われる。

そういうわけで、今や私の個人情報は、みずほ銀行が市場調査などの統計解析のために使うことができるし、私の自宅にダイレクトメールを送るためにも使えることになったわけだ。私が住所を公開しているからといって、SPAM(SPAM缶ならば歓迎だが)を送りつけていいことにはならない。しかし、みずほ銀行は契約により、私にSPAMを送り放題ということだ。

2014-01-pre-Issaquah-mailingのレビュー:N3890-N3899

N3890: Container<Incomplete Type>

一部のコンテナーのvalue_typeに、不完全型(Incomplete type)を許すよう、制限を緩和する提案。

この提案により、以下のようなパターンが合法になる。

// 再帰的なクラス宣言
struct Foo
{
    std::deque<Foo> deq ; 
} ;

クラスは、クラス定義の閉じカッコ、'}'を持って、完全型になる。したがって、クラス定義の中では、クラス名はまだ不完全型なのだ。クラス定義の中でテンプレート実引数にクラス名を渡すと、当然不完全型になる。

ここで、std::dequeの実装が、sizeof(value_type)のような記述をしていた場合、ill-formedとなる。

std::dequeの実装で、sizeof(value_type)のような、value_typeが不完全型であるとill-formedとなるような記述を避けることは可能である。しかし、現行のC++標準規格は、value_typeに不完全型を許していないので、上記のコードがC++98/11/14で通るかどうかは、実装依存である。

有名どころのC++実装で言えば、libstdc++のdequeは不完全型に対応しているが、libc++と、Microsoftの不自由なC++コンパイラーに付属のSTLは、ill-formedとなる。どちらの実装も、この点においては規格準拠である。

しかし、C++98時代から、このような再帰的なクラス定義のパターンを使いたいという需要は相当にあったlibstdc++の多くのコンテナーが、不完全型に対応しているのは、そのためである。

N3890提案は、多くのコンテナーを不完全型に対応させることを提案している。std::arrayのような特殊なコンテナーは対応できないが、set/mapやunordered_set/unordered_mapまで対応するという。

さて、既存のC++実装を、不完全型に対応させるのは、技術的に難しくはない。技術的な困難はないものの、現実的な困難はある。

  • LLVMのSTL実装であるlibc++は、対応可能である。ただし、std::dequeのABI互換性が壊れてしまう
  • GCCのSTL実装であるlibstdc++は、対応可能である。ただし、std::dequeのABI互換性が壊れてしまう
  • 不自由なソフトウェアであるMSVCのSTL実装は、デバック可視化機能のために、コンパイル時定数を維持したい部分がかなりある。このため、std::dequeのようなクラスの対応は予定していない。std::listやstd::forward_listの対応には興味を示している。

また、コンテナーにユーザー定義のstd::lessやstd::hashを与える場合は、その型も不完全型をサポートしていなければ、コンテナーは不完全型対応にはならない。対応しなければ、コンテナーが不完全型に対応しないだけなので、既存のコードが壊れることはない。

libc++のコンテナーを不完全型に対応させた実験的実装が、GitHubで公開されている。

lichray/libcxx at container_incomplete

それにしても、一昔前は、C++の実験的実装といえばGCCだったのに、いまではすっかりLLVMにお株を奪われている。LLVMのコードは読みやすく、ハックしやすいからであるが、このままではGCCの牙城が危うい。

[title要素と論文のタイトルが異なる悪く書かれたHTML] N3891: A proposal to rename shared_mutex to shared_timed_mutex

現行規格では、shared_mutexはtimed mutex(TimeLockable要件を満たす、すわなち、try_lock_for/try_lock_untilを提供している)かつ、shared mutex(同一の、例えばスレッドなどの実行媒体から、複数回ロックできる)である。

とすれば、shared_mutexは、実際には、shared_timed_mutexとしたほうがいいのではないか。そうすることによって、timed mutexの要件は満たさないが、shared mutexとしての要件は満たすクラスを効率的に実装できる自由度を、C++実装に与えることになる。

そういうわけで、現行のshared_mutexを、shared_timed_mutexに変更する提案。

N3892: C++ Ostream Buffers

現行規格では、ストリームに対する出力操作は、競合を引き起こさないことが規定されている。しかし、其の出力がどうなるかについては規定されていない。したがって、複数の実行媒体(execution agent)からストリームに出力した場合の結果がどうなるかは、規定されていない。

このため、C++利用者は、独自の方法で同期を取らなければならない。独立したソースコードは独立した同期方法を取るため、複数のソースコードを混在させることが難しい。そのため、ストリーム出力に対する同期方法は標準化されるべきである。

ストリームの同期方法は、過去にも何度か提案された。

N3535: C++ Stream Mutexesは、ストリームに対するmutexを標準化しようという提案だった。2013年春の会議で、本格的なmutexではなく、バッファーに対する同期であるべきだとする合意がなされた。

それを受けて、N3678: C++ Stream Guardsでは、ストリームに対するバッチ処理という概念のライブラリが提案された。バッチ処理は、mutexでもバッファーでも、あるいは其の両方を組み合わせても実装できる。会議では、単にバッファーを扱うだけにしては、複雑で問題が多すぎると指摘された。

なかなか決まらないので、後発の提案、N3665: Uninterleaved String Output Streamingでは、単に複数の実行媒体から出力操作されても、混ざらずに出力されることが規格上保証された最小バッファー長を規定しようという提案がなされた。これも否決された。

そこで、今回の論文だが、バッファーに対する操作を明示的に行えるライブラリの提案となっている。以下のように使う。

// N3892提案の例
#include 
#include 

int main()
{


{// ブロックスコープ
  std::ostream_buffer bout(std::cout) ;
  bout << "Hello, " << "World!" << std::endl;
}// ここで出力される。

}

std::ostream_bufferは、自動変数として使う。出力をバッファーし、破棄されるタイミングで、混ざらずに一気に出力される。

N3893: C++ Standard Library Active Issues List (Revision R86)
N3893: C++ Standard Library Defect Report List (Revision R86)
C++ Standard Library Closed Issues List (Revision R86)

標準ライブラリに指摘されている既知の問題点集。

[今回最後の不快なPDF] N3896: LIBRARY FOUNDATIONS FOR ASYNCHRONOUS OPERATIONS

この論文は、futureのthenによって指定する継続は、コールバックで指定する継続に比べてパフォーマンスが悪いと指摘する

futureは、処理を発行してfutureオブジェクトが返されたあとに、thenで継続をセットなければならない。thenで継続をセットする前に発行した処理が完了した場合、まず同期が発生してfutureの状態が変更され、しかし継続はセットされていないのでそのままで、そのあとにthenで継続がセットされて、この際にも同期が発生する。

コールバックは、処理を発行する際に、同時に継続もセットするので、無駄な同期が発生しない。

なぜ同期の発生回数にこだわるかというと、一回同期するのに、論文著者によれば、論文筆者の環境では、mutexやアトミック操作による同期は10-15ナノ秒かかる。また、std::futureによってブロックされていたスレッドにコンテキストスイッチして、ブロックから目覚めるのに、3マイクロ秒かかるとしている。

一方、64バイトのUDPパケットをあるホストのユーザースペースのアプリケーションから、別のホストのユーザースペースのアプリケーションまで、10GbEネットワークで送るのにかかる時間は、2マイクロ秒である。

論文筆者は、マイクロ秒単位のパフォーマンスの差が問題になる金融取引などの仕事をしているらしく、パフォーマンスの低いfutureではお話にならないとバッサリ切り捨てている。

しかし、futureもfutureで、利用価値はある。いや、世の中の並列実行は、futureとコールバックだけではない。resumable functionやcoroutineと呼ばれている、函数の栃生で実行を中断、再会できるようなものや、さらにはファイバーなどと呼ばれている、通常のスレッドより軽い協調的なマルチタスクによる実行単位など、様々な方法がある。もちろん、ユーザーが独自実装した方法も使いたい。

論文は、Boost 1.54のAsioを引き合いに出して、多様性があり、拡張性もあるasyncのインターフェースと実装方法を紹介している。

N3897: Auto-type members

non-static data memberの宣言の型指定子にauto指定子を使えるようにする議論のまとめ論文。これは提案ではない。

もし、議論されている内容が提案されて可決されたのならば、以下のようなコードが書けるようになる。

// N3897議論が提案されて可決された場合に書けるようになるコード
struct Foo
{
    auto a = 0 ; // int
    auto b = 0.0 ; // double
    auto * c = this ; // Foo *
    auto d = c ; // Foo *
    auto & e = *this ; // Foo &
} ;

さて、このようなコードを書きたいだろうか。筆者にはよくわからない。論文では、Faisal Valiが実験的な実装を行ったそうだ。

このような機能を追加するには、様々な懸念が噴出しているので、これが提案されるかどうかはわからない。

コンパイラー屋も含む、多くのC++標準化委員が懸念を示している機能なので、なにか説得力のある利用方法を示すとか、現場の利用者からネツレツに使いたいという意見でも上がらない限りは、この機能はこのままお蔵入になるだろう。

もし、具体的な活用方法や、ぜひとも実務で使いたい、コレがなくては不便でならぬ。C++を使うかどうかはこの機能の有無にかかっているという強い意思があるのならば、筆者まで知らせてもらいたい。

N3898 HASHING AND FINGERPRINTING

これは提案ではなく、ハッシュ関数の設計と実装の紹介としての論文のようだ。

ユーザー定義型のハッシュ値を簡単に計算できるようにするために、char, bool, longなどの基本型を複数突っ込めば、ハッシュ値を計算してくれるライブラリの設計と実行を紹介している。

N3899: Nested Allocation

歴史的に、C++の実装では、automatic storageというものは、一般にスタックとよばれる確保済みのメモリ領域から確保している。スタックは環境によって様々ではあるが、かなり強い制限がある。しかし、スタックからメモリを確保するのは高速である。

C++では、allocaなどの例外的な関数を除き、スタックから直接確保するための方法を提供してこなかった。

C99はvariable length arrayを追加した。C++でも、似たような機能をruntime sized arrayとして提案中だ。

また、C++では、non staticデータメンバーにruntime sized arrayを認める提案もしている。この場合、クラスはautomatic storage上に確保しなければならない。しかし、これはクラスのオブジェクトはどのストレージにも構築できるいう、C++の利点が損なわれてしまう。これは極めて例外的な提案だ。

また、現在提案中のstd::dynarrayは、automatic storageに確保できる文脈では確保し、そうでない文脈ではヒープに切り替えるといった、柔軟な対応が可能なライブラリだ。しかし、これはいつスタック上に確保されるのかということが、規格ではなく、実装の都合で決まってしまう。およそ、スタックに確保されることを気にするC++ユーザーは、絶対にスタックに確保されるという保証が欲しいはずだ。

さらに、これらの提案のすべてに、再構築という大問題が立ちはだかる。以下のような問題だ。

// 再構築
void f( std::dynarray<int> & r )
{
    r~dynarray<int>() ; // デストラクターの明示的呼び出し
    new(r) dynarray<int>(2) ; // 再構築。いいのか?
}

int main()
{
    std::dynarray<int> a(1) ; // 構築
    f( a ) ; // リファレンス渡し
}

これはいったいどうなるのだろうか。このようなコードは認められなければならない。しかし、これを認める場合、オブジェクトの寿命がネストしてしまう。

論文では、まずそもそも根本的に、オブジェクトの寿命のネストをサポートするための規格が必要であると主張している。

結び

とにかく、これで2014-01-Pre-Issaquah論文集をレビューし終えた。筆者がドワンゴに入社して二ヶ月近くたつが、C++WG論文をいつもより丁寧にレビューするぐらいしかしていない。ドワンゴ社内は、現場のC++利用者の意見が聞ける環境なので、提案の問題点の発見に役立つ。

また筆者も、社内でC++に提案されている新機能について、論文をレビューしながら社内IRCでチャットという形で解説しているが、この提案というのは、仮に採択されるにしても、正式にドラフト規格に、取り入れられて、C++コンパイラーで実装されて、現場で使えるようになるまで、まず10年はかかる機能ばかりだ。今すぐに役立つ知識ではない。

そして、2014-02-Post-Issaquah論文集もあるので、もうしばらくはこの状態が続く。たまっているC++WG論文をレビューし終えたら、他のC++啓蒙活動も始めようと思う。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

「C++11は十分に枯れて現場で使えてしまうので、もう飽きた。C++11をバリバリに書きつつ、10年後に現場で使えるようになるかもしれないC++17の新機能の話がしたい」という君。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2014-03-16

妖怪ネットワークにRTX810を導入した

筆者の住んでいるシェアハウスである妖怪ハウスのネットワーク環境、すなわち妖怪ネットワークの構築が、一段落した。ついに、YAMAYAのRTX810を導入することに成功したのだ。

RTX810の初期設定は、一般家庭で使うにはかなり変わっているので、結構な設定が必要だった。

まず、初期設定では誰でもログインできるようになっているので、適切にパスワードを設定した。

デフォルトで設定されるファイヤーウォールが不思議だ。まだRTX810独自のコマンドを読むのに慣れていないのだが、どうもデフォルトで設定されるフィルターは、プライベートIPアドレス間での通信、つまりプレイベートネットワーク内のホスト同士での通信を完全に遮断しているように読める。実際に、RTX810を介して無線LAN APにログインできないので、正しいのではないかと思う。

さらに、ファイル共有で使われるSMBプロトコルも遮断しているように読める。

無線LAN APへのログインは滅多に行わないし、行う場合は無線LAN APについているLANポートと有線接続すればいい。しかし、SMBは妖怪ネットワークの住人の間でも多用されているので、これはまずい。このフィルターは削除した。

また、この調査の過程で、妖怪ネットワーク内で、重要な機密性のあるファイルが存在するディレクトリを、意図せずにパスワード無しでSMBプロトコルで公開してしまっている住人を発見したので、注意して直させた。

RTX810を妖怪ハウスに導入するにあたっての問題は、その接続方法であった。

妖怪ハウスネットワークとインターネットを接続するのは、フレッツ光で、ISPからレンタルしているPR-400MIというモデム兼ルーターを使わなければならない。妖怪ネットワークのパフォーマンスの低さは、まともなスイッチングハブを導入することでかなり改善されたのだが、せっかく強力なルーターであるYAMAHAのRTX810があるので、これを活用してみたいところだ。しかし、どうやってRTX810を直接つなげればいいのだろうか。

まず考えられるのは、PR-400MIにRTX810をつなげて、PR-400MIのDHCPを無効にし、プレイベートネットワークはRTX810で引き受けることである。PR-400MIにはPPPoEブリッジ機能もあるので、RTX810は、PR-400MI経由とはいえど、直接PPPoEを話すことができる。これは動くし、実用上は問題ないだろうが、どうも気分的にやりたくない。

PR-400MIは、一体型のように思えるが、実は、モデム部分とルーター部分が内部で独立しており、モデムとルーターの間を、Ethernetでつなげるようになっている。モデム部分から、UNIと書かれたLANポートがでており、ルーターからのLANケーブルが刺さっている。すると、このUNI LANポートにRTX810をつなげば、完全にISPレンタルルーターを介さずにインターネットにつなげるではないか。

問題は、PR-400MIも、必要だということだ。住人の中に、FAXのために光電話を必要とする者がいるので、光電話は必要である。光電話を使うには、PR-400MIか、光電話をサポートしたルーターが必要である。RTX810は、光電話を使うような用途には想定されていないので、当然、光電話機能はない。すると、PR-400MIもUNIポートに接続しなければならない。

すると、気分的にあまりよろしくないが、やはりPR-400MI経由のPPPoEブリッジで我慢するしかないのだろうか。

Twitter上で、UNIをスイッチングハブで分けて、PR-400MIとRTX810のWANを接続すればいいではないかという助言をもらった。それだ。スイッチングハブでUNIを分けるという単純な発想に、なぜ思い至らなかったのか。

そうして、昨日一日作業して、妖怪ハウスのネットワークをRTX810に移行させた。

それにしても気になるのは、スイッチングハブはどうやってUNIとPR-400MIとRTX810をさばいているのだろうかということだ。このスイッチングハブの利用には、ルーターは一切絡んでいないような気がする。3本の接続は、スイッチングハブからは、どれも平等に見えているのではなかろうか。RTX810の発したパケットは、PR-400MIではなくUNIに届いて欲しいのだが、どうやって動いているのだろうか。スイッチングハブからどうやって見分けているのだろうか。

ネットワーク周りも基礎から真面目に学ばなければならない。

そして、RTX810をDNSキャッシュサーバーとして動作させると、nslookupは使えるのだが、digが使えなくなる。

dig example.com

が動かない。DNSサーバーのアドレスは、127.0.1.1であるので、digで指定してみたが、やはり通らない。

dig @8.8.8.8 example.com

は通る(8.8.8.8はGoogleが提供しているDNSサーバー)

nslookupは使えるし、その他のDNS lookupは問題ないようだ。digがなにか特殊なことをしているのであろうか。RTX810に何らかの設定項目があるのだろうか。

しかし、既存の妖怪ハウスの住人が、どうやって貧弱で不安定なネットワークで暮らせていたのか謎だ。筆者がまともなネットワークを構築するまでは、妖怪ネットワークは極めて不安定で遅延もひどかったのだ。(というより、ほとんどの問題は、RTX810導入以前にまともなスイッチングハブをひとつ導入するだけで解決されてしまった)

改善前の妖怪ネットワークは、一度TCPコネクションをはれば、切れることはないものの、それ以外は極めて不安定だった。

詳しく調べていないのでよくわからないが、たとえば、帯域には波があった。実験のために、十分な帯域を持ったインターネット上のサーバーからダウンロードを行ってみると、数秒100Mbpsを超えたと思えば、数秒間何の転送も行われないような、極端な帯域の波があった。わざわざ、誰も帯域を使っていなさそうな時間帯に試験したのにこれだ。また、ブラウザーで新しいページを開くときに、何十秒も待たされることがたびたびあった。DNS lookupが遅いのか、TCPコネクションを張るのが遅いのか、あるいは単に、先ほど観測された帯域の波という謎の現象のせいなのか、よくわからない。

また、リビングに設置されている無線LAN機器もひどかった。BUFFALO製の機器で、最高54Mbpsでしかリンクできなかった。おそらくはIEEE 802.11nに対応していない機器なのだろう。それだけならまだ許せるが、なぜか数Mbps程度のリンク速度しかでない場合がほとんどだった。どんなに適切な場所を探しても、一向にまともなリンク速度がでない。しかも通信も不安定だった。そんなよくわからない無線LANルーター(APモードで動作)をハブ代わりにして、すべてのLANポートにケーブルが刺さっていた。

筆者のネットの利用方法として、ブラウザーでブックマークしたURLを数十個一気に開いては確認して閉じるようなことをしているので、妖怪ハウスのネットワークの不安定さは耐えられないほどであった。

さて、今回、私が使う部分のネットワークは、私が金を出してまともにした。私が使わない部分に関しては、そのままにしてある。ただし、ネットワーク全体がまともになったので、私の使わない部分も恩恵は受けているが、現時点では、私の使わないところの大部分は完全に潜在的な性能を引き出していない。私の責任ではない。理由は後述。

妖怪ハウスにおいて、筆者はリビングの横の部屋に住んでいるのだが、住人の過半数は、リビングからは離れた部屋群に住んでいる。この部屋群に向かって伸びているLANケーブルがささったスイッチングハブのLEDを確認すると、なんと100Mbpsでしかリンクしていなかった。しかも、LANケーブルの先は安物のBUFFALOの無線LANルーター(APモード)につながっていて、もちろんこの無線LANも、IEEE 802.11nに対応していないため、リンク速度は最大54Mbps。ほとんどの住人はその無線経由でネットワークにつながっている。一人だけ、無線LANルーターをハブ代わりにして有線を部屋に引き込んでいる。

この部屋群のネットワークは、物理的に観測しても悲惨である。LANケーブルが無造作に床をはっているし、無線LANルーターも、固定されずに床に落ちている。以前は床にテープで固定していたらしいが、剥がれたらしい。当然だ、床に固定するから蹴り飛ばされるのだ。

あまりにみかねたので、配線だけはすこし直した。LANケーブルを壁にはわせるようにし、無線LANルーターも壁に固定した。

その際に調査を行ったところ、LANケーブルは1Gbpsのリンク速度がでた。すると、100Mbpsのリンク速度しかでないのは、このBUFFALOの機器のせいだろう。

これをまともにするには、8ポート(あるいは部屋ごとにさらにスイッチングハブで分けるのならば4ポートでも可)ぐらいのまともなスイッチングハブと、まともな無線LAN APに取り替えればよい。そうすれば、各部屋に有線LANとまともな無線LANが行き渡る。筆者はこの部屋群は使わないので、さすがにそこに金を出すことはしない。

結局、インターネット回線はフレッツ光なので、帯域は下り200Mbps/上がり100Mbpsだ。したがって、100Mbpsでも、それほどの問題はないと思うかも知れない。しかし、それはあくまでインターネット回線との間の帯域だ。妖怪ネットワーク内には、もっと広帯域が必要なのだ。妖怪ハウスでは、SMBプロトコルによるファイル共有を行っている住人が多い。当然だ。リビングまでストレージを担いでやってきて作業したい者などいるわけがない。そして、住人の大半は部屋群に集中している。この構成では、部屋群の誰かがSMBプロトコルで自分のストレージに本気でアクセスしただけで、部屋群全体のネットワーク帯域がほとんど使い尽くされてしまうはずだ。なぜならば、部屋群は全体で100Mbpsしか帯域がないからだ。

ただ、部屋群の住人は、以前の悲惨なネットワークでも、改善するほどの不満はなかったのだから、それほど帯域を使っていないのかも知れない。実際に聞けば、最近はファイル共有を使っていないという。

ともかく、妖怪ネットワークは快適になった。

Samsung Galaxyにバックドアが発見される

Googleとハード屋が不自由なソフトウェアを世の中に蔓延させるために不毛な労力を注ぎ込んでいるAndroidは、無論、不自由なOSかつ、制限ハードウェアである。

確かに、Androidは、時代遅れの自由なソフトウェアライセンスであるGPL Version 2であるLinuxカーネルを使っているものの、そのlibcは、許諾的な自由ソフトウェアライセンスであるBSDライセンスされたBionicであり、その下に、不自由なバイナリブロブのドライバーが山ほど動いている。そして、Androidを搭載しているほとんどのハードウェアは、極めて屈辱的に制限されている。

ほとんどのAndroidハードウェアは、二つのCPUを積んでいる。ひとつは、Androidや、その上の通常のユーザーランドのソフトウェアを動かす、汎用CPUである。Androidは手足をもがれて不自由ソフトウェアに汚染されたOSであるが、まだ多くの共通部分は公開されているといえる。

もうひとつは、モデムとかベースバンドとかラジオなどという名前で呼ばれているCPUで、電話局との通信の制御に使われている。このCPUが動かすOSやソフトウェアは、完全に閉鎖的でプロプライエタリで、どうしようもないクソだ。我々はこの動作を、たやすく検証することはできない。極めて信頼できない、危うい組み込みのスパイである。

参考:The second operating system hiding in every mobile phone

さて、今回、Replicantという完全に自由なAndroidディストリビューションを開発しているプロジェクトが、邪悪な意図の存在が極めて強く示唆されるSamsungのほとんどのGalaxyデバイスに、バックドアを発見したと発表した。

SamsungGalaxyBackdoor - Replicant
Replicant developers find and close Samsung Galaxy backdoor — Free Software Foundation — working together for free software

どうやら、このベースバンドCPU上で動くプロプライエタリな怪しいOSと、GalaxyにプレインストールされたAndroidに搭載されたカーネルモジュールが協調して、ファイルシステムに無制限にアクセスできる、その意図が疑わしい機能が含まれているという。これは、バックドアとして悪用可能である。

完全に自由なAndroidディストリビューションを開発するReplicantでは、そのような疑わしいカーネルモジュールなど搭載することはなく、したがってこのベースバンドCPUの上で動くプロプライエタリOSと強調することはなく、したがって、このようなバックドアの疑いが強い機能の動作を阻止できる。

既存のSamsung Galaxy利用者は、今すぐSamsung Galaxyデバイスのバッテリーを引っこ抜いて窓から放り投げるか、少なくともプレインストールされた不自由Androidを完全に削除し、新規にReplicantをインストールして、Samsungに説明を要求するべきである。

あるいは、ハンロンの剃刀に従えば、これはベースバンドOSが、デバッグ目的などで手軽なストレージを扱いたかったので付け加えたあくまでデバッグ目的の小汚い機能が、製品版でも取り除かれずにそのまま残ったのかも知れない。一般に、この手のQualcommなどのハード屋は、どうしようもないほどバカでマヌケで底なしに無能であり、そういうことは十分に考えられるからだ。

ここにいるぞ。中は想像以上に悲惨だ。コードが公開される時--すなわちネット上にばら撒かれるせよ、あるいはもっと悲惨なことに、正式にビジネスパートナーに提供されるにせよ--その時はすでに、全開発者は、新規のプロジェクトにとりかかっている。コードがコンパイルされて、製品として店先に出荷されるまでには、6ヶ月ほどのラグが存在する。その時には、すでに技術は移り変わっているので、誰も大昔のものには関心を払わない。すでに出荷されたものの不具合を修正することに、何の利益もないし、企業的理念も存在しない。コードをパッチするなんて簡単なことであると、私は常に思っていたのだが、管理職の連中にとっては、大事でも何でもないことであった。

BNC43xxの開発における、本当にクソすぎたことを教えてやろう。我々は3ComとかLinksys(Ciscoに買収される前後両方)とかAppleとかD-Linkとかに、リファレンスデザインを販売していた。理屈の上では、全社とも、同じリファレンスデザインを受け取るわけだ。だが、もしそのうちの一社が我々のコードのバグ報告をしたならば、パッチされたコードを受け取るのは、バグ報告したその一社のみだ。結果として、我々のコードには、#ifdef(COMS)とか#ifdef(LINKSYS)とかで、それぞれ専用のパッチを有効にしてあった。まだバグを発見できていない他の会社は、我々が壊れていると知っている状態のアップデートを受け取っていた。会社にとっても悲惨だし、会社の顧客にとってはもっと悲惨だ。

さらに、全社に向けて、そのようなパッチの内容を知らされないまま、ソースコードリリースも提供されていた。そのために我々は、コード変換器と呼ばれるものをビルドステップに挟んでいた。これはコード全体にわたって、一部のCプリプロセッサーシンボルを展開するので、#ifdef(COMS)とか#ifdef(LINKSYS)といったものが、消されるようになっていた。これにより、全社とも、それぞれ異なったソースコードリリースを受け取ることになっていた。顧客会社に渡すコードは、それぞれ別々にコンパイルした変換済みのコードであった。

さらに、それぞれの会社が独自に開発者を雇って、独自拡張を施しているし、彼らは我々のブランドではなく、製品を"Cisco"とか"Linksys"とかのブランドで出荷したがっていた。そのため、著作権表記とかを全部書き換えた以外は同一内容のソースコードを、単に顧客会社が全部自前で書いたように見せかけるために作っていた。

もう俺は足を洗って業界から身を引いたよ。

I hear you. It's so much worse than you can imagine. By the time the code g... | Hacker News

読者はこのような悲惨極まりない環境で開発されたハードとOSの利用を拒否せずんばあらざるなり。もはや自由不自由という問題ではなく、根本的にハナがヒン曲がるほどの腐臭を放つほど腐っているのだ。腐りきっているのだ。クソなのだ。クソすぎるのだ。この世の中にこのようなもはやこれを罵るに適切な罵倒言葉がまだ発明されていないが、その何かであるほどに悲惨なものが、存在を許されて言い訳がない。この腐った業界もろとも滅びるがよい。

仮想環境越しにCubase 5を動かす

Running Cubase 5 in a virtual machine (vmware) - YouTube

Cubaseというプロプライエタリな音楽作成用のUSB接続のデバイスとその操作用のこれまた不自由なソフトウェアを、仮想環境上で動かしたWindows XPから扱うデモ。

仮想環境であることによるオーバーヘッドは、リソースを富豪的に使うことにより解決できると豪語している。その物言いがあまりにもおもしろかったので紹介。

この動画では、VM内でCubaseを使っている。今日の強力なコンピューターをもってすれば、外部USBサウンドカードを、仮想環境に接続することは可能なのだ。たとえ、たとえ、ホストOSがLinux[訳注:Linuxとは単なるカーネルであり文意不通。おそらくはGNU/Linuxのことであろう]や、Macであったとしてもだ。VMに複数のコアを割り当てることができるので、CPU性能は問題にはなり得ない。

もし君が、そうだな、8コアCPUと大量のRAMを持ってるのならば、まともなパフォーマンスを得るために、5コア程度と数GBのRAMをVMに割り当てるぐらいのことは、当然やるだろ?

[訳注:仮想環境が] USBサポートをしてくれたおかげで、ネイティブシステム並みのレイテンシーが得られるぜ。

もう、HDDにCubase用のパーティションをこしらえる必要はなくなるのだ。

[訳注:Cubaseの不自由なソフトウェアは、Windowsのような不自由な上に使いづらいOS上でしか動かないので、GNU/LinuxやGNU Hurdのような、まともなOSを利用する者は、わざわざCubase操作用にパーティションを区切って醜悪なWindowsを入れなければならない]

なんとも富豪的発想だ。

2014-03-15

MozillaがMetro版Firefox開発中止を発表

Update on Metro | Future Releases

今週のはじめ、筆者はリードエンジニアとリリースマネージャーに、Windows Metro版のFirefoxの開発中止を指示した。開発チームはよくやってくれたが、Metroプラットフォームを取り巻く環境を考慮すると、1.0をリリースするのは、間違いだった。

Mozillaは世界をより良くするためにソフトウェアを開発している。しかし、我々は戦いを選ばねばならない。今や我々は、Firefox 1.0をリリースした時ほどちっぽけな存在ではないが、我々の労力は、我々が誓った目標を達成するために、集中して振り向けねばならない。我々の競合相手の強大さと、労力の多大さにより、我々は労力を適切に集中させなければならないのだ。

2012年末、筆者がMetro用Firefox開発チームを立ち上げた時(もうMicrosoftは、Metroという名称を使っていないが、我々内部で話すときは、未だにその名前を使っている)、MetroはWebの次の戦場のように思えた。Windowsは巨大な環境であり、Microsoftはこの新しいプラットフォームを強烈に打ち出していた。当初、我々は完全に閉めだされているようであった。我々はなんとかMetroをオープンにして、(ARMベースのRTは未だに閉鎖的だが)、開発を始めた。

何ヶ月もたち、開発チームが開発し、テストし、製品としての完成度を高めていくと同時に、我々はMetroの受け入れ具合を観察していた。見る限り、シェア率増加は完全に水平線である。例えばだ。毎日、何百万人もの人間が、リリース前のデスクトップ版Firefoxをテストしている。しかし、Metro環境の活発な利用者は、一日1000人程度しかいなかった。

これにより、我々は厳しい選択に迫られた。リリースすることはできるが、現実の環境であまりテストされていないものを表に出すことになる。つまり、現実に使われるようになると、多くのバグが発見されるだろうということで、多くの後出しの開発や設計やQAテストの労力がかかる。リリースして後出しの作業をしないという選択肢は存在しない。製品をリリースしたのならば、一生サポートし続ける必要があるのだ。戦いを選ぶという観点から言えば、これは割り合わない戦いだ。労多くして益少なし。

だから、引き上げることにした。これは、Metroが明日にでもおおはやりして、我々は急いで追いつかなければならないリスクを抱えることにはなるが、今現在、利用者が全く受け入れ姿勢を示していないプラットフォームに多大な投資を行うことを考えると、取るべきリスクだ。コードは残る。市場規模はともかく、我々はこの製品に多大な投資をしたと感じているが、しかし、より多くの人々に届く場に労力を集中する。まだこのコードにやるべきことはたくさん残っている。

Johnathan Nightingale, VP Firefox

Metroという不自由極まりない閉鎖的、制限的な環境で動くソフトウェア、いや、WindowsというプロプライエタリなOS用の自由なソフトウェアを開発するのは、本来不毛である。しかし、そのことによって、少しでも多くの人々が、不自由な肝教で動く自由ソフトウェアではあるが、自由のよさを認識してくれれば、完全に不毛というわけではない。

筆者は早く皆が自由の価値に目覚めることを願ってやまない。

2014-03-14

2014-01-pre-Issaquah mailingのレビュー: N3880-N3889

[なかなか悪くないHTML] N3880: Improving the Verification of C++ Programs

ようやく、C++論文で許せるマークアップのHTMLを読んだ気がする。

この論文は、C++にプログラムの検証を支援するための機能の必要性を提案している。

プロジェクトを始めるにあたって、どのプログラミング言語を選ぶかということは重要である。プログラミング言語ごとに利点や欠点があるので、考慮される。考慮に上がる対象に、検証可能性は重い。標準規格に、検証のための標準の規格がないのは、C++の利用を妨げる要因となっている。

この論文は、検証を標準規格でサポートするための必要性を提起するものであり、具体的な新機能の提案は含まれていない。ただし、現在のC++で改良できる分野として、いくつかの点を上げている。

たとえば、static_assertのメッセージを改良するだとか、API設計の妥当性を検証するためにコンパイルエラー自体をテストする機能であるとか、ill-formedの詳細な分類とか、文脈に依存したソースコード上の情報を取得する機能(リフレクションなど)や、より高度なassertionライブラリ、テストの際にのみ実行されるコード片の登録機能、検証プログラムの自動生成、などを挙げている。

まだ、検証力の必要性の提起だけなので、具体的にどのような新機能が提案されるのか、また実装可能なのか、興味深くはある。

[PDFも修正されるべき] N3881: Fixing the specification of universal-character-names

UCNに関する訂正。

C++11では、Unicode文字はすべてPhase of Translationのできる限り早い段階でUCNに変換するなどという定義にしてしまったため、真面目に実装しようとすると、色々と問題が出てくる箇所がある。また、変換前のソースコードを再び読まなければならない時もある。未定義な挙動もある。

そのため、いままで規格がカバーしきれていなかった範囲の挙動まで詳細に指定する文面の変更を行う提案。

具体的にどのような問題があるかは、論文を参照。

[PDFも使いづらいという現状を認識すべき] N3882: An update to the preprocessor specification

これもN3881と似通った論文。

忌まわしき太古の遺物であるCプリプロセッサーには、未定義な挙動が多々ある。当時としては、実装の自由度を持たせるために適切であったことも、Cプリプロセッサーが十分に枯れ尽くした今となっては、異なる実装間の移植性を妨げるだけである。

それに、今の最新のコンパイラー(GCC 4.9, Clang 3.4, 不自由なMSVC 12, 不自由なEDG/ICC 13)を比較すれば、もはや挙動の差異は微々たるものである。

そこで、今までCプリプロセッサーで未定義の挙動とされていた部分を、今の有名な実装の挙動を追認する形で、規格で詳細に定義する提案。

具体的にどのような問題があるかは、論文を参照。No! You cant haz cheeze burger!

N3883: Code checkers & generators

コードチェッカーとジェネレーターというか、コンパイル時リフレクション機能の提案。

この論文が大雑把に提案している機能は、コンパイル時に、コンパイラーのASTの一部をC++ユーザーに提供し、また生成する力を与えようというものである。

例えば、以下のようなクラスがあったとする。

// 人を表現するクラス
class Person
{
private :
    std::string name ;
    std::string address ;
    double weight ;

    // その他多くのデータメンバー

public :
    // 比較関数の宣言
    bool operator == ( Person const & rhs ) const ;
} ;

このクラスのoperator ==を実装したい。3個のデータメンバーがすべて等しければ等しいとみなすようにしよう。これは、以下のように書ける。

// 比較関数の定義
bool Person::operator == ( Person const & rhs ) const
{
    return  this->name == rhs.name &&
            this->age == rhs.age &&
            this->weight == rhs.weight &&
            // その他のデータメンバーの比較
            ;
}

しかし、このようなコードを手書きするのは、間違いの元である。もしPersonの宣言を変更した場合、operator ==も変更しなければならない。またまた間違いの元である。このような機械的なコードは、自動生成したい。

それには、コンパイル時にクラスのメンバーという情報を取得し、また取得した情報に基づいてコードを生成する力が必要だ。すなわち、ASTの取得と改変能力が必要だ。

N3883提案は、そのような強力な力をC++に与える力強い提案である。


// ドライバー
class EqualityDriver
{
    constexpr EqualityDriver(const ClassDecl & classDecl)
    {
        class_name = classDecl.getTypeName() ;
        for ( auto & field : classDecl.fields( ) )
        {
            members.emplace_back( field.getName( ) );
        }
    }

    meta::vector<meta::id_name> members;
    meta::type_name class_name;
} ;

// 比較関数生成のためのパターン
$define OperatorEqGenerator( EqualityDriver driver )
{
  bool $driver.class_name::operator==(const $driver.class_name & rhs) const
  {
    return true
      $for (auto member : driver.members) {
        && $member == rhs.$member
      }
    ;
  }
}

// 比較関数の生成
$OperatorEqGenerator( Person ) ;

N3883提案は、$define, $use, $for, $if, $switchという新しいキーワードで、ASTを取得、あるいは改変する。

一度このような生成規則を書いてしまえば、あとは、全データメンバーを比較するあらゆるクラスに適用できる。


struct Foo
{
    int x ;
    int y ;
    bool operator == ( Foo const & ) const ;
} ;

struct Bar
{
    double d ;
    bool b ;
    bool operator == ( Bar const & ) const ;
} ;

$OperatorEqGenerator( Foo ) ;
$OperatorEqGenerator( Bar ) ;

いや、ちょっと待て。先ほどのクラスPersonだが、weightというデータメンバーの値は、比較の対象にならないようにできないのか。第一、人は体重が増減しても、同一人物ではないか。

もちろんできる。

// 体重を考慮しないドライバー
class EqualityDriver
{
    constexpr EqualityDriver( const ClassDecl & classDecl )
    {
        class_name = classDecl.getTypeName();
        for ( auto & field : classDecl.fields() )
        {
            // 特定の名前のデータメンバーをフィルターする
            if ( field.getName() == "weight" )
                continue ;

            // 残りは追加。
            members.emplace_back(field.getName());
        }
    }
    meta::vector<meta::id_name> members;
    meta::type_name class_name;
} ;

これぐらいたやすいことだ。そう、N3883提案ならば、C++はASTの一部に干渉できるのだ。

他にも、具体的なコード例は省略するが、構造体の配列を、構造体の各データメンバーの配列に変換したり、既存の関数を置き換えたり、文字列からenum型を生成したりと、やりたい放題だ。

そう、もはやCプリプロセッサーマクロは時代遅れの遺物になるのだ。これから#defineなどと書く幽霊プログラマーは、後ろ指をさされてひと目を忍んで地下に潜って、かつての混沌とした日々を懐かしむぐらいしかすることがなくなるであろう。$if, $else, $switchにより、従来のCプリプロセッサーマクロの役割は、完全に代替される。

そう、テンプレートメタプログラミングも時代遅れの遺物になる。もはやTMPでレイトレーシングをする岡山の陶芸家はお呼びではないのだ。

コンセプトですら、N3883により、改善される。

この提案は、AngularJSから影響を受けており、またその設計には、Clang APIをそのまま持ってきている。

唯一の不満点は、その文法が悲惨なことだ。$はPHPを彷彿とさせるものがある。

文法に議論の余地はあるものの、このような提案は、さらに発展させるべきだ。

[PDFも一新されるべき] N3884: Contiguous Iterators: A Refinement of Random Access Iterators

Contiguous Iteratorという概念を標準ライブラリに追加する提案。

Contiguous Iteratorとは、連続したストレージ上に確保されている要素の集合を指し示すイテレーターであることを保証するものである。

つまり、以下のようなことが保証される。

// Contiguous Iteratorの例
template < typename contiguous_iterator >
void f( contiguous_iterator iter )
{
    auto next = iter + 1 ;
    &*iter + 1 == &*next ; // true
} 

つまり、イテレーターの指し示すオブジェクトのポインターを+1した結果のポインターと、イテレーターを+1した結果のイテレーターの指ししめすオブジェクトのポインターが、等しいことが保証される。

これは、たとえばC時代のAPIにポインターを渡すとか、連続したメモリであることを検出してmemcpyに切り替えるなどのアルゴリズムの最適化など、連続したストレージ上に確保されていることが保証されていることを利用したコードが書けることを意味する。

[PDFを廃止する提案] N3886: A Proposal to add a Database Access Layer to the Standard Library

データベースアクセスのためのインターフェース的なライブラリを標準ライブラリに追加する提案。

論文には、具体的なインターフェースの設計が書かれているので、興味のある人は呼んでもらいたい。このブログにコピペして解説することはしない。

インターフェースの設計は、バックエンドのデータベースとして、SQLベースのリレーショナルデータベースを想定している。

このような共通のインターフェースを標準化する理由としては、データベースアクセスのためのAPIは、実に多数あり、しかもその多くが、大昔のCの設計になっている。モダンなC++風の洗練されたインターフェース設計のライブラリが存在するべきである。

[一貫性のために論文フォーマットとしてPDFを廃止せよ] N3887: Consistent Metafunction Aliases

[PDF注意] N3655で、ほとんどのメタ関数には、エイリアステンプレートを用いて、metafunction_tが作られたが、tuple_elementだけは欠けていた。そのため、tuple_element_tを付け加える提案。

また、すべてのメタ関数にそのようなエイリアスが必要というわけではない。そのようなエイリアスが必要もないメタ関数だってある。そのため、いつ_tにすべきかという今のガイドラインは、あまりにも範囲が広すぎるという議論もしている。

[PDFで公開するようでは、お先真っ暗] N3888: A Proposal to Add 2D Graphics Rendering and Display to C++

2Dグラフィック描画ライブラリをC++に付け加える提案。

なぜ必要なのかという理由から始まって、グラフィック関連の様々な事情を説明している、結構長い論文。これはいずれ、別の記事で詳しく紹介したい。

今の予定では、土台としてcairoを用い、C言語によるインターフェースに、機械的な変換ルールを定義して、C++風のインターフェースに書き換えるようにしている。

その変換ルールも提案している。

[高濃度のPDF汚染を検出] N3889: Concepts Lite Specification

Concept Liteの仕様書案

ドワンゴ広告

この記事は、ドワンゴに昼過ぎに出社してボードゲームをやる合間に書いた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

最近のUbuntuの動向

先月、色々と忙しくて観測対象から外れていたUbuntuの動向をまとめた。

[Phoronix] Ubuntu To Abandon Upstart, Switch To Systemd

Ubuntuが、将来的にUpstartからSystemdに移行する意向を発表した。

[Phoronix] Ubuntu Systemd Plans: Will Be Default By Ubuntu 16.04 LTS

Systemdは、Ubuntu 16.04 LTSにはデフォルトになるという計画が発表された。

[Phoronix] Shuttleworth On Google Go, Unity 8, Ubuntu Phone, Etc

また、開発者サミットでShuttleworthが発表した内容によると、Mirは16.04 LTSでデフォルトになる予定だそうだ。Canonical内部ではGoが使われているそうだ。

2014-03-13

ValveがOpenGLデバッガー、VOGLを公開した

GNU/Linuxに不自由なソフトウェアを蔓延させる目的で活動してるValveが、VOGLという自社製のGNU/Linux上で動くOepnGLのデバッガーをGitHubで公開した

ValveSoftware/vogl

まだ開発段階で、ろくにドキュメントもないようだ。早期に公開するという姿勢は評価したい。残念ながら、彼らのソフトウェア流通プラットフォームは邪悪のDRMがかかった不自由ソフトウェアを蔓延させるものなのだが。

最近このブログがつまらなくなったという指摘について

最近、このブログがつまらなくなったという意見を聞いた。実際、この二ヶ月、色々とあってブログの執筆は、いつもより少なかった。

これは一時的なもので、その理由は、環境の変化だ。

1月中旬に、私は京都から東京に引っ越さなければならなかった。引越というのは結構面倒な作業なので、まずその作業に時間を取られていた。

さて、東京に着いたあとも、住んでいる家の整備で色々と時間を取られていた。シェアハウスに住んでいるから、まだこの程度ですんでいるが、これが完全に一から環境構築となると、途方もない作業が必要になる。

ようやく、妖怪ハウスのネット環境は整えたものの、まだ色々と、自宅は作業をする環境になっていない。

まず、自宅にはまともな椅子がないし、まともなディスプレイもない。椅子とディスプレイは慎重に選ぶべきものであるし、いいものは高いので、まだ購入していない。

それから、自宅の押入れを何とかしなければならない。とりあえず、私の荷物を入れるスペースとして、押入れの上の段を確保したのだが、この押し入れは、垂直方向に高いので、空間を効率的に活用するためには、何らかの仕切りが必要になる。その仕切りをどのように作成するかが、目下の問題だ。

押入れの大きさは、高さ80cm、奥行き80cm、幅160cmといったところだ。高さはもっとあるのだが、上30cmほどは、押入れ自体に棚がついている。

しかし、高さ80cmというのは、まだ高すぎる。これを二つか三つほどに区切って、垂直方向に空間を活用したい。

最初考えたのは、押入れにはまる大きさの本棚を押し込んでしまうことだ。しかし、それではあまりに仕切りが細かすぎる。

あるいは、ラックを入れるという手もある。しかし、ラックの価格を調べた所、押入れをラックで満たすには、3万円はかかる計算になる。

引き戸式の収納ケースのようなものを積み重ねるという案もある。しかし、やはりこれも、押入れを収納ケースで満たすには、数万円はかかるだろう。

金はないこともないが、そんなに大金を使いたくない。もっとハックして安く上げたい。

資材屋で角材と板を買ってきて自作するという手もある。これは、材料費ならば5千円もあればできるはずだが、はたして十分な強度と仕上がりになるだろうか。

とにかく、自宅の環境を整えないことには、自宅でブログ執筆ができない。

では、会社ではどうか。会社ではブログ執筆ができる環境が整っている。しかし、誘惑も多い。ボードゲームというとても抗いがたい誘惑がある。

しかし、ボードゲームは一日にせいぜい1,2時間ほどだ。残りの時間は何をしているのかというと、今は論文のレビューをしている。

大半の読者は、私の通常の記事を期待しているのかも知れないが、私はC++ Evangelistである。C++の啓蒙家を名乗る以上、最新の論文にはすべて目を通し、解説しなければならない。また、ドワンゴでは、提案されている新機能に対し、現場の意見を聞くことができるので、極めて規格と論文のレビューに素晴らしい環境となっている。

そうなると、必然的に、いつもより解説に力が入る。解説に力を入れるということは、時間がかかるということだ。いつもなら、「簡易レビュー」という名前で、論文の概要程度の解説だったのだが、今回は、詳細にまで踏み込んだ解説をしている。これにはかなり時間がかかるが、その代わり、記事の質は大幅に向上している。

引越と環境構築に時間を取られたのと、いつもより詳細に解説していることにより、論文一本一本の解説の執筆に時間がかかり、そのために、他の雑学的なブログ記事の執筆は、現在、あまり行っていない。しかも、post-Issaquah mailingまで公開されているので、この状態はしばらく続く。

C++以外の記事を期待している読者もいるかもしれないが、やはり私は、C++啓蒙家なので、ここはおろそかにはできないのだ。

取り急ぎ、雑学的なブログ記事を読みたい人は、Amazon.co.jp: 江添亮: 江添のほしい物リストで何かを買って妖怪ハウスに送れば、まとまった量の商品が届いた時に、その商品について何かを書くつもりだ。もし、アマゾンを経由しないで直接送りたい場合は、以下の住所に送ってもらいたい。

筆者にブログのネタになる品物を直接送りたい場合の宛先:
郵便番号:165-0027
住所:東京都中野区野方5-30-13 ヴィラアテネ401
宛名:江添亮

その他の英語圏のニュースの紹介などの記事は、恒例のC++WGの論文のレビューは片付くまでは、しばらくは数が少なくなるだろう。

妖怪ハウスのネット環境改善作業

筆者が妖怪ハウスにやってきたとき、妖怪ハウスのネット環境は悲惨だった。

まず、ISP提供のモデム兼ルーターと、無線LANルーターが床に落ちている。配線も他の様々なコードとからみあって、わけがわからない状態であった。5LDKの家でLANケーブルが床を無造作にはっている。

そして、無線LANルーターが貧弱すぎて遅かったし、すぐに途切れた。有線でもやはり遅かったし、時々動かなくなることが会った。

住人の話では、「夜に特に遅くなる。0.01Mbpsしかでないときもある。誰かがP2P型のファイル共有かなにかで帯域を使っているのだろうか」ということであった。

そもそも、ISPとの契約書すらなくしていた。一体、回線がどういう契約なのかすらわからない。VDSLだろうか。光ファイバーが来ているのだろうか。それを調べようにも、機器が床に落ちて、複雑に絡み合ったコードの中に埋まり、確認ができなかった。

色々と調べた結果、回線はフレッツ光だった。いくら住人と客人で使うからと言って、200Mbpsもあれば十分なはずだ。なぜこんなに遅いのか。

その帯域というのも、それほど狭くはない。試してみれば、100Mbps以上は余裕で出る。問題は、帯域は広いのだが、なぜか帯域を観測すると波がある。数秒100Mbps以上でて、数秒落ち込むというサイクルを繰り返している。

それに、この家の住人で、P2P型ファイル共有ソフトウェアを使えるだけの十分な知識を持っていそうな人間は数人しかいない。プライベートネットワーク内におけるファイル共有はかなり発見できるが、これは、不自由なWindowsや不自由なMac OS Xがデフォルトで設定しているものにすぎない。それに、これは1Gbpsのプライベートネットワーク内で完結しているものであり、インターネット上には出て行かない。

まてよ・・・ひょっとしてルーターのせいなのだろうか。考えてみれば、ISP提供のルーターは、このようなシェアハウスの環境を想定していない。何人も住んでいて、客人も来て、それぞれに数台はコンピューターを使っていることを考えれば、ISP提供の非力なルーターが耐えられるわけがない。

それにしても、なぜこんな環境で、住人は暮らせているのだろうか。インターネットは、もはや水や電気と同じく、基本的人権に加えられるべきインフラだ。こんなに貧弱なネット環境はありえない。

仕方がないので、筆者自ら、妖怪ハウスのネット環境を強力に作り変えることにした。ルーターが確認できないほどこんがらがった電源ケーブル、LANケーブルを整理し、各部屋に送るLANケーブルも壁に固定しなければならない。また強力なネットワーク機器が必要だ。

筆者は秋葉原に行き、様々な機器を購入した。だいぶ痛い出費だったが、仕方がない。

まず、電源ケーブルを整理した。複数の電源タップに、テレビやルーター機器などの抜いてはいけないコンセントと、抜いてもいいACアダプターなどが、乱雑にささって、ゴルディアスの結び目よろしく、複雑に絡み合っている。残念ながら、ここではかの大王が取ったような画期的な手法を取ることはできない。一つ一つ結び目を解いていかなければならないのだ。

そもそも、なぜISPレンタルルーターと、無線LANルーターが、床に落ちて電源ケーブル類と絡まっているかというと、Ethernetポートのためだ。ISPレンタルモデムと無線LANルーターのポートすべてに、LANケーブルが刺さっている。元は本棚の上に設置していたそうだが、ケーブルに引っ張られて床に落ちたまま、放置されていたのだ。

Ethernetポートが足りないから、こういうことが起こるのだ。ポートがルーターにしかないから、そこに刺してしまうのだ。この問題を解決するためには、ポート数の多いスイッチングハブを使い、ルーターからケーブルを取り除く必要がある。たまたま、同居人が5ポートほどあるBUFFALOのハブを持っていたが、これをネットワークに接続すると、なぜか家中のネットワーク全体が不安定になる。壊れているのだろうか。

秋葉原で色々と探した挙句、筆者はNETGEAR GS116v2 16ポート ギガビットノンインテリジェントスイッチ (省電力製品) GS116-200JPS (本体ライフタイム保証)日本電気 AtermWG600HP PA-WG600HPを買った。

特に選択に意味はない。BUFFALOという安かろう悪かろうの粗悪な製品を避けたかったからだ。

さて、もともと、ルーターからLANケーブルを排除する目的で、Netgearの16ポートのスイッチングハブを導入し、ISPレンタルルーターへの接続を一本にしたところ、なんと、ネットワークの不安定さが、だいぶ解消されてしまった。なるほど、ISPレンタルの貧弱ルーターのEthernetポートをすべて埋めると、負荷がかかりすぎてしまうのかもしれない。それにしても、スイッチングハブというのは、実は意外と高度なことをしているのだな。いままで、スイッチングハブの存在を侮っていた。単にLANケーブルを分割する程度の認識しか持っていなかった。今回買った、このNetgearの製品は、ノンインテ入りジェントという名称が入っているが、どうやらこれは、同社の他の製品に比べればノンインテリジェントという意味らしい。さらに高価なスイッチングハブには、ハブ自体にQoS機能などがあり、ハブにログインして設定できるのだという。

さて、そして、今までの56Mbpsでしかリンクできない貧弱なBaffaloNECの無線LANルーターを、NECのルーターで置き換えた、このNECのルーターの設定UIはとてもクソで、初回ログインはクソみたいなわけのわからない、しかもまともに設定できずに使い物にならない、そもそもまともに設定して突破することもできない、自称簡単設定UIを表示し、しかもその設定を済ませなければ詳細な設定UIにアクセスできないとあって、非常に難渋した。幸い、このNECのクソUIのルーターに詳しい知人が、一度ログインしたまま、もう一度ログインすると、通常の詳細設定UIが表示されるという助言をもらったので、なんとか、この自称簡単設定UIを突破することができた。いったい何なのだ、このクソUIは。

しかも、詳細設定のUIも、設定の保存と設定の摘要が分かれているという、これまた訳のわからないクソUIだった。いったい、どこのバカがこんなクソUIを設計したのだ。

さて、NECのルーターのUIは、本当に本当にとてもとても排泄物だった。最初、設定のために、ルーターモードにしたNECのAtermとコンピューターをLANケーブルでつないで、ルーターにログインし、望みどおりに設定してからアクセスポイントモードにして、そのあとに妖怪ハウスのネットワークに接続した。すると、なぜか設定が反映されていない。いったいこれはどういうことだ。再びルーターモードに戻すが、やはり設定されている。APモードにすると設定されない。もしやこれは・・・

なんと、このNECのクソ無線LANルーターは、ルーターモードとAPモードで、設定が独立しているのであった。いったいどこのトチ狂ったバカが、どんな薬物を摂取したら、こんな設計になるのだ。根本的に腐っている。

さて、設定に関して、とても糞だったNECの無線LANルーターだが、とりあえず無線LANとしては、そこそこの仕事をしてくれた。ただし、いずれは業務用のいい無線LAN APを導入したい。

さて、Netgearのスイッチングハブと、NECの無線LANルーター(APモード)を導入したところ、妖怪ハウスのネット環境は、なんとかなりマシになってしまった。なるほど、スイッチングハブは侮れないのだな。そして、無線LANも、安物を使うべきではないのだな。

しかし、まだダメだ。まだ満足できない。まだ遅い。どうも、DNS検索が遅いように思う。このISPレンタルルーターがDNSキャッシュサーバーとして動いているようだが、遅すぎてキャッシュの役割を果たしていない。むしろ逆に遅くなっている。そして、TCPコネクションを張るのにも、やや時間がかかっているように思われる。やはり、根本的に、このISPレンタルルーターは非力なのだ。DNSサーバーはこちらで設定することもできるが、住人全てにその設定ができるわけではない。

やはりここは、強力なルーターを導入しなければならない。100台規模の機器を余裕でさばけるような強力なルーターがほしい。しかし、そのような強力なルーターはなかなかに高価だ。さてどうしよう。

なんと、そのルーターが無料で手に入った。なんとも親切な人が、余っているからと、新品同様の YAMAHAのRTX810を送ってくれたのだ。RTX810だと。それはちょっとした中小企業に導入して会社内のネットワークをそれひとつでさばけるような強力なルーターではないのか。そんないいものを。

さて、どうやってこのルーターを導入すればいいのだろうか。ISPレンタルルーターをよく観察したところ、どうやら、モデムとルーターの一体型に思われたこの機器は、内部で二つに分かれているようだ。モデム部分からUNIという名称でEthernetポートがあり、そこにルーター部分からLANケーブルがつながっている。これを差し替えれば、ISPレンタルの貧弱ルーターを使わないということが可能だ。

ただし問題は、電話が使えなくなるということだ。ある住人は、仕事上、自宅にFAXを置かなければならないため、難しい問題だ。なぜFAXを必要とするかというと、旧態依然の保守的でクソみたいな裁判所が、いまだにFAXを使い続けるからだ。日本の裁判所は、FAXのような平文で送信する信頼できない通信方法ではなく、電子署名と暗号化による暗号理論的に適切な通信方法に、今すぐ移行しなければならない。すでに行政の多くは、移行している。裁判所がそれをしないのは甚だしい怠慢である。

さて、それはともかく、せっかくYAMAHAのRTX810があるのだから、試験的に導入を試みた。これが・・・なかなか難渋した。

RTX810は、HTTPサーバーとして機能して、ブラウザー上から操作する簡単なUIを提供している。このUIは、NECのクソUIよりは、いくらかマシであったが、やはり使いづらい。

RTX810は、telnet/ssh/シリアルポートから接続して、直接文字列でコマンドを送信することで、設定することもできる。ただし、これがあまりよろしくない。

まず、まともなシェルがない。そして、文字コードが忌々しきシフトJISである。しかも、勝手に行数を区切って--more--的な表示をする(ただし、シフトJISで日本語なので、よくわからない)

わざわざシフトJISロケールを生成して、ターミナルからシフトJISを扱うのも面倒だ。とりあえずteeコマンドでファイルに吐き出してみたが、ド素人丸出しである。iconvで変換すればいいのではないかとおもったが、どうやらiconvは入力をバッファしてしまうらしく、動かない。入力をバッファせずに文字コード変換を行うソフトウェアに、nkf -uがある。これでようやく、出力の意味がわかった。しかし、なぜ日本語なのだ。なぜシフトJISなのだ。YAMAHAの顧客は不自由なWindows利用者だけなのか。どんなに小規模なネットワークであっても、管理者がWindows利用者というのは考えられないのだが。

あとで知ったことだが、RTX810では、以下のコマンドを使うと、まともな出力になるということが判明した。これがデフォルトになっているべきである。


console character ascii
console columns 200
console lines infinity

忘れずにsaveしておこう。

さて、設定は終わり、実際にISPレンタル機器のUNIに接続してみたが、どうも動かない。いや、厳密に言うと動く。ISPとのPPPoEは通り、もちろんインターネットにつながっているのだが、なぜかDNSの設定がうまくいっていないようだ。それも、DHCPでDNSサーバーのIPアドレスを通知するところがうまくいっていない。なぜだろうか。

この問題は、ついに、なぜ動かなかったのかわからなかった。何度か試行錯誤するうちに、いつのまにか動くようになった。おそらく、最初はadministratorコマンドをうち忘れていたのではないかと思う。

さて、RTX810の初期設定では、DHCPで割り当てるIPアドレスは、192.168.100.xとなっている。住人の中に、わかりにくいから192.168.1.xから割り当ててくれと言う人間がいたので、dhcp scopeを設定した。設定したところ、どうやら間違えてしまったようで、RTX810のDHCP機能が動かなくなってしまった。dhcp scopeの設定方法を、もう少し学ばなければならない。第一、ネットマスクなる用語の意味を、正確に把握していない。

DHCPが動かないだけなのだから、DHCPにたよらずに、自前でIPアドレスを主張すればよかったのだが、早急に復旧させる必要があるため、そこには思い至らなかった。

RTX810は、RS-232cポートを持っており、シリアルケーブルで接続することでログインすることもできる。あいにくと、私のラップトップに、そのような古典的なポートは存在しない。今や、シリアルポートといえばUSBやSATAのたぐいを言うのであって、RS-232cではない。住人の一人に、シリアルポートのついた昔のラップトップを所有している人がいたが、残念ながら、ケーブルがない。

しかたがないので、スイッチの同時押しで、RTX810を初期化した。

初期化後、再び一から設定を始めたが、もうすっかり慣れたと見えて、こんどは短時間で設定できた。

ただし、初期化したことは正解であった。RTX810を譲ってくれた人を疑うわけではないが、やはり念の為に、初期化をしておくべきだろう。

さて、RTX810を試験的に導入した結果だが、完全に世界が変わった。ネットワーク内の遅延が劇的に改善され、実に快適で強力なネット環境が構築された。いつか人を集めて、各人ごとに持てるだけのコンピューターを持ってきてもらい、妖怪ハウスネット環境のストレステストを行いたいものだ。ただし、それには、もっと強力な業務用の無線LAN APも必要となるだろう。

なるほど、ネットワークの構築作業というのは、意外と楽しい。ハードウェアや構成を変更すると、パフォーマンスが劇的に変わるというのは、とても楽しい。いままで、ネットワーク管理者というのは、つまらなそうな職業だと思っていたが、なかなかどうして、やりがいのある仕事だ。いままであまりよろしくなかったネットワークのパフォーマンスを大幅に向上させた時の快感はたまらないものがある。自宅で中小企業に入れるレベルの機器を使って、数十台規模のネットワークを構築できる経験ができるというのは恵まれているといえるだろう。

とりあえず、今はISP提供のレンタルルーターを使っている。住人にFAXを使う人がいる以上、難しい問題だ。ネットワークに負荷がかかると予想されるとき(客を大勢呼んだ時とか)に、RTX810に差し替えるつもりだ。ただし、いずれは、RTX810に置き換えたい。

電話の問題は、二回線引けばいいのだが、残念ながら、その住人にはそれほど金がない。ただし、裁判所がセキュリティ的にどうしようもないFAXを使い続ける以上、やはり専用の線をひくべきではあるのだが。いや、むしろまともな暗号理論の知識がない裁判所が変わるべきなのだ。裁判所、お前はクソだから改善しろ。数学的に証明された手法を否定して、平文で送る(しかも受け取り側の電話というのは、普通は人が張り付いておらず放置されているので、誰に読まれるかわからない)クソみたいなセキュリティがザルのFAXを、即刻廃止しろ。裁判所はクソだ。

妖怪ハウスの配線とネット環境は改善された。もうLANケーブルが床をはうことはない。もう貧弱な無線LANに悩まされることはない。トイレの中にまで無線LANが届くので、トイレにも作業用に電源タップを配置した。

まだ妖怪ハウスに改善すべきところは多々あるが、また後ほど、改善作業を終わらせてから記事を書く。

他にも欲しい、高価なネットワーク機器はある。またそれ以外にも欲しいものがある。レトロゲームのソフトや本体や周辺機器を揃えたい。これらは不自由なコンピューターではあるが、どうしても昔の思い出は捨てがたいのだ。現在、ファミコン、スーパーファミコン、ニンテンドー64、ゲームキューブ、PS2、PS3がある。ただし、PS2とPS3は新しすぎるのでレトロゲームの定義には当てはまらない。

もし、読者の中に、レトロゲームのソフトや周辺機器を妖怪ハウスに寄贈したい人がいれば、大歓迎だ。いつでもゲームをやりに遊びに来て欲しい。いまのところ、以下のものが欲しい。

ファミコン、スーパーファミコン、ニンテンドー64、ゲームキューブのソフト。クソゲーも歓迎する。スペランカーや元祖西遊記スーパーモンキー大冒険のような有名なクソゲーもある。また、ファミコンのディスクシステムもあるので、ディスクシステム用のソフトも欲しい。

スーパーファミコンのコントローラー(あと2本)とマルチタップ

ニンテンドー64のコントローラー(あと3本)、コントローラパック(いくつでも)

ゲームキューブのコントローラー(あと3本)、ゲームボーイプレイヤー(中古市場で手に入れるには、本体ごと購入する必要があり、高価)

ゲームボーイ、ゲームボーイポケット、ゲームボーイカラー、ゲームボーイアドバンスの本体と周辺機器とソフト(私が50分以内にRTAできるキャッスルヴァニア 〜暁月の円舞曲〜が特に欲しい。現在、中古市場価格が高止まりしていて、高価)

その他のレトロゲーム本体とソフト

2014-03-12

2014-01-pre-Issaquah mailingのレビュー: N3872-N3879

N3872: A Primer on Scheduling Fork-Join Parallelism with Work Stealing

これは提案ではなく、Fork-Joinにおける実装戦略の入門書的な論文。

Fork-Joinというのは、処理の単位を発生させて、ある地点で、発生させた処理が全て終わるまで待つものだ。Clik風の文法で書くと、以下のようになる。

// Clik風文法によるFork-Join
// オリジナルのスレッドが実行開始
e() ; // オリジナルのスレッドが逐次実行
spawn f() ; // 並行して実行される処理を生成
g() ; // fとは並行して実行される
sync ; // f, gの処理が両方終わるまで待つ
h() ; // 逐次実行

さて、ここで疑問が二つある。

  1. fとgを実行するスレッドは何か?
  2. hを実行するスレッドは何か?

fとgを実行するスレッドは何か?

Fork-Joinという概念による並列実行のスケジューラーの実装方法としては、Work-stealingというものがある。これは、MIT Cilk, Intel Clik Plus, Microsoft PPL, OpenMPで使われている。work stealingの概要としては、まずスレッドが処理を作る。スレッドが処理の実行を終えたら、そのスレッドは泥棒(thief)となり、別のスレッドで未実行のままたまっている処理を横取りする。

上の例では、spawn f() ; で処理が作成されている。さて、その処理を作成したオリジナルのスレッドは、fとgのどちらの実行をすればいいのだろうか。それには、ふたつの戦略がある。

  • Child Stealing: fは泥棒スレッドに盗まれるようにし、オリジナルのスレッドはgを実行する
  • Continuation Stealing: オリジナルのスレッドがfを実行する。オリジナルのスレッドの実行の継続は、別の泥棒スレッドに任せる。

これは、一見すると、些細な違いのように見える。しかし、ループの中で処理を延々と生成していくようなコードでは、この違いが問題になってくる。例えば以下のコード、

// 戦略の違いが問題となるコード
for ( int i = 0 ; i < n ; ++i )
{ spawn f( i ) ; }

sync ;

さて、このコードを実行すると、f(0)から、f(n-1)までの処理が生成される。ここで先ほどの二つの戦略を当てはめてみると。

Child Stealingでは、spawn f( i )を実行したあと、オリジナルのスレッドは、未実行の処理の数にむとんちゃくでfor文の実行を続けるので、f(i)が爆発的に生成されてしまう。これにより、未実行の処理を記録しておくリソースなどが浪費される。

Continuation Stealingでは、オリジナルのスレッドが、まずf(0)を実行しに行く。for文の実行は、泥棒スレッドに任せる。この戦略では、未実行の処理が爆発的にたまることはない。泥棒スレッドがあるだけ効率的に処理を生成し、実行できる。ただし問題は、本来実行していたスレッドとは別のスレッドが実行を継続することになるので、たとえばレジスターやTLSなど、退避、復帰させなければならないデータがたくさんあり、コストがかかる。

また、Child Stealingは、純粋にライブラリだけでも実装できる。Continuation Stealingは、コンパイラーのサポートが必要だ。

それに、Continuation Stealingは、一見逐次実行に見えるのに、実行するスレッドが変わるので、初心者を混乱させる。

hを実行するスレッドは何か?

さて、syncによってjoinしたあと、hを実行するスレッドは、いったいなんだろうか。これには二つの実装戦略がある。

  • Stalling: オリジナルのスレッドが実行する。
  • Greedy: 最後に処理を終えたスレッドが実行する

Stallingの、オリジナルのスレッドが実行を再開するのは、とてもわかりやすい。ただし、それはオリジナルのスレッドが、すべての処理が終わるまで待たなければならない。そのためにStallingと呼ばれている。うかつに時間のかかる処理を、オリジナルのスレッドが盗んでしまうと厄介だ。

Greedyは、最後に処理を終えたスレッドが実行するので、スレッドが何もしないで待つ必要がない。ただし、オリジナルのスレッドとは別のスレッドが実行を継続する可能性があるので、TLSなどがうまく動かないし、TLSもうまく動かすようにしようとすれば、相当のスレッド環境の退避、復帰のコストがかかる。それに、わかりにくい。

TBBとPPLはStallingをサポートしている。Cilkは、Greedyをサポートしているが、Stallingをサポートする実験的なライブラリもある。OpenMPは、なんとまた、どちらもサポートしている。

[汚らしいド素人の書いたHTML] N3873: Improved insertion interface for std::{unordered_,}map

論文のタイトルは"Improved insertion interface for unique-key maps", 論文のHTMLのtitle要素は、"Improved insertion interface for std::{unordered_,}map"という一貫性に欠けるマークアップ。しかも、物理的な改行が意味を持つコードをマークアップするのに、既存の意味的にもふさわしいpre要素やcode要素を使わずに、div.code { white-space : pre-wrap ; }しているという、汚らしいド素人が書いたであろうマークアップの論文。

mapとunordered_mapにemplaceのようなものを追加する提案。

既存のmapとunordered_mapのemplaceは、キーが存在する場合、要素の挿入を行わない。問題は、要素の挿入が行われなかったとしても、依然として、実引数で渡したオブジェクトは、ムーブ後の状態になる可能性がある。

// emplaceの例
std::map<std::string, std::unique_ptr<Foo>> m ;
m["foo"] ; // キー"foo"を挿入

std::unique_ptr<Foo> p(new Foo) ;
// キーはすでに存在する
// pはムーブ後の状態になっている可能性がある
auto res = m.emplace("foo", std::move(p)) ;

挿入を行わないのならば、ムーブしなくてもいいし、実際、そのように実装することもできる。ただし、規格は上の例で、pをムーブ後の状態にすることを禁止していないし、実際にムーブ後の状態にするライブラリ実装もある。なぜかというと、emplaceは、実引数から、std::pair< std::string, std::unique_ptr<Foo> >のオブジェクトを生成するのだが、この生成は、キーの検索の前に行われることが、規格上許されているからだ。規格上許されている以上、そのように実装しても何の問題もない。

そこで、キーが存在した場合は、実引数のオブジェクトに何の変更をもくわえないことを保証した、新しいメンバー関数、emplace_stableを追加する提案。

// emplace_stableの例
std::map<std::string, std::unique_ptr<Foo>> m ;
m["foo"] ; // キー"foo"を挿入

std::unique_ptr<Foo> p(new Foo) ;
// キーはすでに存在する
// pはムーブ後の状態になることはないことが保証されている
auto res = m.emplace_stable("foo", std::move(p)) ;

なぜ、既存のemplaceをemplace_stableの挙動にしないのかというと、どうも、うまい文面案が思いつかないらしい。なんともプラグイン的な解決方法だ。

提案では、もうひとつ、empalce_or_updateというメンバーを付け加える。これは、キーが存在する場合でも、上書きムーブする。


std::map<std::string, std::string> m ;
m["foo"] = "bar" ;

std::string value{ "hoge" } ;

// キーが存在するので上書きされることはない
m.emplace_stable( "foo", value ) ;
m["foo"] ; // "bar"

// キーが存在するが上書きする
m.emplace_or_update("foo", std::move(p)) ;
m["foo"] ; // "hoge"

emplace_or_updateは、emplace_stableがあれば、効率を落とさず簡単に実装できる。なぜならば、emplace_stableは、イテレーターと、挿入を行ったかどうかをpairで返すからだ。


auto it = m.emplace_stable("foo", std::move(p));
if (!it.second)
{
    it.first = std::move(p); 
}

とはいえ、こんなコードをいちいち書きたくない。標準ライブラリで提供されているべきだ。

[クソみたいなPDF] N3874: Light-Weight Execution Agents

スレッドとかタスクとかSIMDとかベクトル実行とか、様々な名称で呼ばれている、light-Weight Execution Agent(軽量実行物)の定義を与える提案。

Execution Agentとは、実行の単位の名称である。

C++11では、スレッドを導入し、C++に並列実行の道具を与えた。

Execution Agent(実行物)とは、すでに規格で定義されている用語(§30.2.5.1 paragraph 1)だ。スレッドは、「ブロックされていない限り、いずれ実行が進む」("should eventually make progress if they are not blocked.")と定義されている。これは、とても強い保証を持っている。

ところで、C++11で入ったスレッドというのは、たとえばPOSIXのpthreadをモデル化したものであり、多くの実装ではOSの提供するスレッドである。このようなスレッドは、とても重たい。しかし、そのような重たいものは、大量に生成すると、リソース使用量の点でコストがかかる。軽い並列処理には、もっと軽い単位のExecution Agentが使われるべきである。すでに、そのような提案はあるが、みな用語がバラバラである。その根底にある基本的なExecution Agentという概念を、共通化してまとめて定義しよう、と、こういう提案である。

まず、Foward progress(実行が進む)保証について考察する。これにはいくつかの保証の強弱が考えられる。

Concurrent execution
スレッドのような、いずれ実行が進むという強い保証
Parallel execution
スレッドプールやFork-joinのような、弱い保証。クリティカルセクションの使用にも難あり。
SIMD execution
SIMD演算のモデル化。これはやや特殊な保証。
Parallel+SIMD execution
ParallelとSIMDを組み合わせて、両方の良いとこどりをねらった保証。ただし、この保証の存在理由には疑問もある。

また、スレッドの紐付けられた状態という点からも考察できる。たとえば、TLSや、this_thread::get_id()や、ロック所有するスレッドという点だ。

論文は最後に、いくつかの疑問を提示している。

[おぞましいPDF] N3875: Run-time bound array data members

実行時にサイズを指定できる配列をクラスのデータメンバーとして持つことができるようにする提案。

ただし、Cとはだいぶ違う方向だ。そして、名前も、実行時サイズ配列(runtime sized array)ではない。

まず、文法をひと通り見ていくことにしよう。

// 文法例
struct runtime_size_bound_class
{
    char [] runtime_bound_array ;

    // array constructor
    runtime_size_bound_class( std::size_t size )
        : runtime_bound_array[ size ]
    {
        // ...
    }
} ;

他にも色々と文法案が提案されているが、どれもこれも一様に気持ち悪い。

まず、データメンバーの宣言文法から見ていこう。これは、実行時束縛配列(runtime bound array)と呼ばれていて、以下のように宣言する

type [] name ;

なぜこうならなければならないのか。当初、runtime bound arrayの文法は、通常のtype name [] ; になる予定だったのだが、それだと、既存のCの構造体のテクニックとかぶってしまうのだ。

// 非常によく使われているテクニック
struct X
{
    std::size_t size ;
    char buf [] ;
} ;

int main()
{
    constexpr std::size_t size = 100 ;
    X * ptr = reinterpret_cast< X * >( std::malloc( sizeof(X) + size ) ) ;
    ptr->size = size ;
}

そのため、文法を変える必要があったのだ。

実行時束縛配列のデータメンバーは、複数持つこともできる。

// 複数個持つ例
struct X
{
    char [] a ;
    char [] b ;

    X( ) : a[ 1 ], b[ 2 ]
    { }
} ;

さて、runtime bound arrayのサイズは、array constructor(配列コンストラクター)と呼ばれるコンストラクターで指定する。

runtime_size_bound_class( std::size_t size )
    : runtime_bound_array[ size ]

array constructorは、メンバー初期化子の文法を拡張して[]でサイズを実行時に指定する。

array constrcutorは、必ず、クラス定義の中で定義しなければならない。

// 間違いの例
struct X
{
    char [] a ;
    X() ;
} ;

// ill-formed
X::X() : a[1] { }

初期化も、通常通りだ

// 初期化の例
X() :
a[1], // デフォルト初期化
b[1](), // 値初期化
c[1]{} // リスト初期化
{ } 

さて、runtime bound arrayをデータメンバーに持つクラスは、runtime size bound class(実行時サイズ束縛クラス)と呼ばれる。runtime size bound classをデータメンバーに持つクラス、runtime size bound classから派生するクラスも、runtime size bound classとなる。

runtime size bound classのオブジェクトは、自動変数として使うことしかできない。つまり、一切の動的に確保する操作は禁止されている。たとえばnewできないし、std::vectorのvalue_typeとなることもできない。

// 禁止例
// ill-formed
new runtime_size_bound_class ; 
// ill-formed
std::vector< runtime_size_bound_class > v ;

runtime size bound classへのsizeofは禁止されている。

// sizeofは許可しないィィィッ!
struct X
{
    char [] a ;
    X() a[1] { } 
} ;

// ill-formed
std::size_t size = sizeof( X ) ;

なぜdynarrayではダメなのかというと、dynarrayで自動ストレージを実行時サイズ確保しようとすると、実装にコンパイラーマジックが必要になるからだ。C++は歴史的にコア言語とライブラリを分割している言語である。C++11では、std::initializer_listという例外が追加されたが、あれは例外中の例外で、基本的には、コア言語とライブラリは直接関わらない。

そのため、ライブラリを実装できる機能は、コア言語で提供されているべきである。そのような機能が、実行時束縛配列というわけだ。実行時束縛配列を使えば、dynarrayが実装できる。

さて、論文では、この提案の他にも、様々な提案をしている。

非inlineコンストラクター

コンストラクター定義をクラス定義の外に書きたい。しかし、配列のサイズの指定方法は、実装の都合上、クラス定義の中になければならない。そこで、メンバー初期化子だけ、inline definition(インライン定義)という名前で、クラス宣言に書くことができる案も、論文に書かれている。

// 提案
struct X
{
    char [] a ;

    // インライン定義
    X() : a[1] { }
} ;

// 本物の定義
X::X() // メンバー初期化子はすでに指定されているので書けない
{
// ...
}

多次元配列

現在の提案では、一次元配列しかサポートしていないが、文法を多次元に拡張することもできる。

// 多次元実行時束縛配列
struct X
{
    char [][] a ;

    X( std::size_t x, std::size_t y )
        : a[x][y]{}
    { }
} ;

sized constructor

サイズコンストラクターといって、コンストラクターをクラス定義の外に書く文法の別の提案。これはDaveed Vandevoordeの提案。

// sized constructorの例
struct X
{
    char [] a ;
    int x ;

    X( std::size_t size, int x ) sizeof( a[size] ) ;
} ;

X::X( std::size_t size, int x ) : x(x)
{
// ...
}

相変わらずだが、Daveed Vandevoordeの提案する文法は、毎回キモい。彼はEDGという不自由なC++コンパイラーフロントエンドの開発者であるので、とりあえず非曖昧でパースしやすい文法を再優先で考案するのだろう。

[PDF早く滅んでくれ] N3876: Convenience Functions to Combine Hash Values

unordered associative container(unordered_map, unordered_multimap, unordered_set, unordered_multiset)は、一般にはハッシュとよばれる仕組みで要素を管理するコンテナーである。具体的には、value_typeから短時間で計算できる短い情報量のハッシュ値を計算して、ハッシュ値同士の比較を行うことで、定数時間の複雑性を可能にしている。

問題は、value_typeからハッシュ値を計算する方法が必要だということだ。標準ライブラリは、基本型やstd::stringなどの標準ライブラリには、ハッシュ値の計算方法を提供している。ただし、ユーザー定義型については、利用者がクラステンプレートstd::hashを特殊化するか、あるいはクラスで実装してテンプレート実引数で渡すなどして、ハッシュ値の計算方法を実装しなければならない。

適切なハッシュ値の計算というのは、とても難しい問題である。平均的なプログラマーがたやすく扱える問題ではない。

たとえば、以下のクラスを考える。

// 顧客クラス
class Customer {
public:
    // ...

    std::string getFirstname() const;
    std::string getLastname() const;
    int getAge() const;
} ;
bool operator== (const Customer&, const Customer&);

このようなクラスのオブジェクトのハッシュ値を計算したい。ところで、都合の良いことに、std::stringやintといった型は、すでに標準ライブラリによって、ハッシュ値を計算する実装が提供されている。これを使って、以下のように実装してはどうか。

// 非常に問題のあるコード例
class CustomerHash
{
public:
    std::size_t operator() (const Customer& c) const
    {
        return  std::hash<std::string>()(c.getFirstname()) +
                std::hash<std::string>()(c.getLastname()) +
                std::hash<std::string>()(c.getAge()) ;
    }
} ;

std::unordered_set<Customer,CustomerHash> coll;

このコードにより生成されるハッシュ値は、極めて質が悪くなる。ハッシュ値は、単に足しあわせてはいけないのだ。

ではどうすればいいのか。筆者はこのレビューを書くにあたって、Donald Knuth先生の大著、The Art of Computer Programming Volume 3を読んだが、やはり、適切なハッシュ値の計算を書くのは難しい。コンテナーという利用目的にあった効率的なハッシュ値を計算しなければならない。ハッシュ値の計算は高速に行われるべきだが、生成されるハッシュ値の質が低くては元も子もない。

そこで、複数のハッシュ値から、まあまあ使える程度のハッシュ値を生成するライブラリを、標準で入れてはどうか。

たとえば、Boostには、そのようなライブラリが存在する。

Combining hash values - 1.35.0
Function template hash_combine - 1.35.0

hash_combineは、たとえば、以下のように実装できる。

// hash_combineの実装例
template <typename T>
void hash_combine (std::size_t& seed, const T& val)
{
seed ^= std::hash<T>()(val) + 0x9e3779b9
+ (seed<<6) + (seed>>2);
}

これは、最高のハッシュ値の計算方法ではないが、単なる足し算よりはいくらかマシな、複数のハッシュ値のハッシュ値の計算方法だ。

議論のしどころはたくさんある。たとえば、seedを直接公開しないようにして、もっといい実装ができる余地を残すなどだ。

[冗長すぎるPDF] N3877: Centralized Defensive-Programming Support for Narrow Contracts (Revision 3)

防衛的プログラミングをサポートするための標準ライブラリ。Bloombergが出したこの論文は、その格調高さに反比例して、中身は薄すぎる。文章量だけは無駄に常用で長いが、本質が薄っぺらい。

要するに、中身はCプリプロセッサーによるassertマクロに毛が生えたようなものだ。assertに引っかかった時の挙動を指定できたり、例外が投げられたりといった機能があるだけのassertだ。

筆者はCプリプロセッサーを使ういかなる機能にも反対しており、この提案にも当然ながら反対する。

[あまりにも冗長なPDF] N3878: Extensions to the Concept Introduction Syntax in Concepts Lite

この提案には、まだ文面案がないので、このレビューの解釈は間違っている可能性がある。そもそも、文法が大幅に変更される可能性がある。

Concept Liteについては、もう十分に有名になったので、いまさら説明するまでもないだろう。Concept Liteは、C++11がまだC++0xと呼ばれていた時代に、一旦はドラフトに入りながら、標準化委員会内でconcept mapを暗黙に生成するべきか、明示的に記述させるべきかで意見が二分されたコンセプトの、テンプレート実引数のチェック部分だけを切り取った、軽量版のコンセプトだ。

たとえば、2種類のイテレーターFor1, For2をマージして、Outというイテレーターで出力可能かどうかを判定するconstexpr関数Mergeableの宣言が、以下のように書かれていたとする。

// Mergeable
template < typename For1, typename For2, typename Out>
constexpr bool Mergeable() ;
// 定義省略

さて、このconstexpr関数をConcept Liteに使いたい場合は、以下のように記述する。

// Concept Liteの例
template < typename For1, typename For2, typename Out >
    requires Mergeable< For1, For2, Out >()
void merge( For1 p1, For1 q1, For2 p2, For2 q2, Out o ) ;

これは冗長で書くのが面倒だ。以下のように書けるようにしてはどうか、という提案。

// N3878提案
Mergeable{ For1, For2, Out }
void merge( For1 p, For1 q, For2 p2, For2 q2, Out o );

このように書けば、最初の長ったらしく書いたものと同じように扱われるようにする提案だ。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3879.pdf

もうすこし順序立てて解説する。まず、従来のunconstrained templateが、以下のようだとしよう。

// unconstrained template
template < typename C >
void function( C ) ;

このテンプレート仮引数Cに対して、UnaryConceptというconstexpr関数を適用して、constrained templateにしたいとする。

// constrained template
template < typename T >
constexpr bool UnaryConcept() ;

requires句を使うと、以下のように書ける。

// requires句を使う例
template < typename C >
    requires UnaryConcept<C>() ;
void function(C) ;

これは面倒だ。そのため、今のConcept Liteの提案は、以下のようなシンタックスシュガーを提供している。

// 便利なシンタックスシュガー
template < UnaryConcept C >
void function(C) ;

class/typenameと書くべきところに、直接constexpr関数名を指定できるのだ。

それを延長して、以下のように書けるようにする。

// N3878提案
template < UnaryConcept { C } >
void function( C ) ;

そして、さらに突き進めて、以下のように書けるようにする(はず、あるいは論文が間違っているのか)

// N3878提案
UnaryConcept { C }
void function( C ) ;

テンプレートの冗長な文法が、だいぶ簡略化された。いや、簡略化し過ぎで、個人的には落ち着かない。しかし、プログラマーというものは、簡単な文法を好むものであるから、むしろこのくらい大胆に簡略化したほうがいいのかもしれない。

この提案されているシンタックスシュガー的な文法が、どのように変換されるのか。まず、以下のようなコード

// N3878提案
SomeConcept{ A, B, C }
void function( A, B, C ) ;

において、SomeConceptはconstexpr関数名である。braceで囲った識別子一つ一つについて、テンプレート仮引数として指定したことになる。

// シンタックスシュガー変換後
template < typename A, typename B, typename C >
    requires SomeConcept< A, B, C >()
void function( A, B, C ) ;

もし、すでに宣言したテンプレート仮引数を使った場合は、ill-formedとなる。たとえば、以下のようなコード

// ill-formedな例
template < typename A, SomeConcept{ A, B } >
void function( A, B ) ;

は、以下のように展開されるので、

// 展開後
template < typename A, typename A, typename B >
    requires SomeConcept{ A, B {
void function( A, B ) ;

ill-formedとなる。

ところで、Concept Liteでは、constrained関数テンプレートを宣言する新しい文法、terse notationを提案している。これは聡明な読者ならば、いまさら説明するまでもないであろうが、念の為に説明しておくと、以下のようなコードが、

// terse notationの例
void sort( Container & c ) ;

以下のように書いたものとみなされる。

// 上記のterse notationと同等のコード
template < Container __Contaiener >
void sort( __Container & c ) ;http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3879.pdf

もちろんこれは、以下のような意味だ。

// さらに展開後
template < typename __Container >
    requires Container<__Container>()
void sort( __Container & c ) ;

そう、聡明な読者ならば、もう気がついているだろう。N3878提案の拡張は、このterse notationにも適用できる。

// terse notationのN3878拡張の例
void sort( Container{C} & c ) ;

これは、以下と等しい。

// 同等のコード
template < typename C >
    requires Container<C>()
void sort( C & c ) ;

なぜ、これが役に立つのか。現在のterse notationは、同じコンセプトを満たす別の型を複数、仮引数に取りたい場合、使うことができない。

たとえば、以下のコードは、

void f( SomeConcept a, SomeConcept b ) ;

以下のコードと同じ意味である。

template < typename __SomeConcept >
    requires SomeConcept<__SomeConcept>()
void f( __SomeConcept a, __SomeConcept b ) ;

したがって、もし、aとbが違う型で、どちらの型もSomeConceptを満たして欲しい場合は、terse notationは使えない。面倒でも従来のやり方で書かなければならない。

// 従来のやり方
template < SomeConcept A, SomeConcept B >
void f( A a, B b ) ;

N3878拡張を使えば、上記と同じ意味を、terse notationと組み合わせることにより、以下のように書くことができる。

// N3878提案
void f( SomeConcept{A} a, SomeConcept{B} b ) ;

また、N3878提案で宣言された名前は、宣言されたことになるので、例えばterse notationでも面倒な以下のようなコードが、

// 面倒なTerse Notationコード
void f( RandomAccessIterator first, RandomAccessIterator Last ) ;

以下のように書ける。

// N3878提案
void f( RandomAccessIterator{R} first, R last ) ;

N3878拡張は、新しいテンプレート仮引数を宣言するので、たとえば、以下のようなコードはill-formedとなる。

// ill-formed
void f( RandomAccessIterator{R} first, RandomAccessIterator{R} last ) ;

なぜならば、これは以下と同等の意味になってしまうからだ。

// ill-formed
template < RandomAccessIterator R, RandomAccessIterator R >
void f( R first, R last ) ;

また、現在のConcept Liteの提案では、変数テンプレートもconstrained templateにでき、また、変数宣言の型引数の代わりに使うことができるとしている。

// constrained変数テンプレート
RandomAccessIterator r = std::find( p, q, r ) ;

これは、読者のような本物のC++プログラマーには、いまさら説明するのは失礼に当たるかも知れないが、念の為に解説すると、以下のような意味である。


template < typename __RandomAccessIterator >
    requires RandomAccessIterator<__RandomAccessIterator>()
__RandomAccessIterator r = std::find( p, q, r ) ;

一貫性を保つため、N3878拡張は、constrained変数テンプレートにも適用できる。

// N3878提案
RandomAccessIterator{R} r = std::find( p, q, r ) ;

これは、rの型名に名前をつけることができるという点で、素のterse notationより優れている。decltype(r)などと書きたくはない。

また、提案では、以下のような文法にも触れている。

// どこまで本気かわからないコード
auto{T} t = foo() ;
// Tはtの型

これは・・・いやはや

[明示的PDF警告] N3879: Explicit Flow Control: break label, goto case and explicit switch

これは面白い。

この提案は、break label, continue label(Javaと同等), goto case 定数式, goto default(C#と同等), explicit switch文(C#と同等)

break labelとcontinue labelは、ネストしたfor, while, do-whileから抜けるのに使うことができる。

// break labelの例
beginning_of_the_loop:
for ( auto && elem : v )
    for ( auto && elem : w )
    {
        break beginning_of_the_loop ;
    }

// continue labelの例
for( auto && elem : v )
{
    middle_of_the_loop:
    for ( auto && elem : w )
        for ( auto && elem : x )
        {
            continue middile_of_the_loop ;
        }
}

goto case 定数式は、switch文の中で、caseラベルを指定してgotoするのに使うことができる。

// goto case 定数式
switch( cond )
{
    case 0 :
        break ;
    default :
        goto case 1 ;
}

explicit switchは、caseラベルひとつひとつが、ブロックスコープを持つ。これにより、次のcaseラベルかdefaultラベルに到達した時点で、switch文を抜ける。もうbreakを書き忘れて、下まで突き抜けてしまうという、しょうもないが人間であるがゆえに起こりうるバグに悩まされることはない。また、わざわざブロック文を使わずとも、ブロックスコープになっているので、変数の宣言も楽になる。

// explicit switchの例
explicit switch( cond )
{
    case 1:
        // ...
    case 2 :
        // flag == 1の場合、ここは実行されない
}

連続するcaseラベルは、ひとつのブロックスコープにまとめられる。


explicit switch( cond )
{
    case 1 :
    case 2 :
        // ブロックスコープ開始
        // cond == 1 or 2の場合、ここが実行される
        // ブロックスコープ終了
}

caseラベルがブロックスコープを持つということは、変数ももちろん、スコープに従う。


switch ( cond )
{
    case 1 :
        int x = 0 ;
    case 2 :
        int x = 0 ; // エラー、おなじスコープ
}

explicit switch ( cond )
{
    case 1 :
    // {
        int x = 0 ;
    // }
    case 2 :
    // {
        int x = 0 ; // OK、別のスコープ
    // }
}

ドワンゴ広告

この記事はドワンゴの勤務中に書かれた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0