2015-07-29

GitHub運営により言葉狩りが行われている

WebMConverterというffmpegのAviSynthのGUIフロントエンドのGitHubレポジトリで、GitHub運営により規約違反の暴力的な言葉が使われたとして削除の警告を受けたことによる変更があった。

https://imgur.com/QC51FZz · nixxquality/WebMConverter@c1ac0ba

https://imgur.com/QC51FZz

文脈は、「バカでも使える」という意味で使っている。

変更では、for Retards(池沼どもでも使える)をfor Gits(クソ野郎どもでも使える)に変えている。

しかし、githubはgit(クソ野郎)という暴力的な言葉を含むのだが、それはいいのだろうか。

2015-07-22

C++標準化委員会の文書 2015-05 post-Lenexaのレビュー: M4531-N4544

N4531: std::rand replacement, revision 3

めでたくdeprecatedされたrandの代わりになるお手軽に使える乱数ライブラリ、randintの提案。

randintは関数テンプレートとなっていて、整数型に対して特殊化できる。

// -10から10までの間のint型の乱数を生成
auto a = std::randint( -10, 10 ) ;
// 0Lから10Lまでの間のlong型の乱数を生成
auto b = std::randint( 0L, 10L ) ;

randintの乱数を生成するために、スレッドごとにdefault_random_engine型のオブジェクトが予測不可能な状態に初期化される。つまり、プログラムの実行ごとにrandintの結果は変わる。

乱数エンジンの状態を再び予測不可能な状態にするには、std::reseed()を呼び出す。

reseedに値を指定すると、状態を予測可能にできる。これは、デバッグ目的に使える。

その他に、乱数生成を関数オブジェクトとして引数に取らない版のshuffle, sampleアルゴリズムが追加される。

N4532: Proposed wording for default comparisons

クラスにデフォルトの比較演算子を生成する提案の文面案。

クラスにvirtual基本クラス、virtualメンバー関数、mutableメンバー、ポインター型の非staticデータメンバー、ユーザー提供されたコピー/ムーブコンストラクターと代入演算子はデフォルトの比較演算子は生成されない。

N4533: Make exception-specifications be part of the type system, version 3

例外指定を型の一部に含める提案。

N4534: Data-Invariant Functions (revision 3)

サイドチャネル攻撃を防ぐためのライブラリ。

value<T>の形で利用して、値の比較ができる。値によって外部から観測可能な物理的挙動(実行時間やメモリアクセスパターンなど)が異なる場合、SONO物理的挙動を外部から観測することで、値が推測できてしまう。valueライブラリは、物理的挙動の差をなくしてくれる。

今回の提案では、barrierが入っていたり、イテレーターの範囲の値がそれぞれ等しいか比較するequal、条件でどちらかのイテレーターの範囲をコピーするcopy_conditional、イテレーターを進めるlookupが入っている。

N4535: Feature-testing preprocessor predicates for C++17

機能テスト推奨で提案されていた__has_includeと__has_cpp_attributeをC++17に追加する提案。

N4536: clamp: An algorithm to 'clamp' a value between a pair of boundary values (Draft) -

clamp( value, min, max )の提案。

#include <functinal>

int main()
{
    auto a = std::clamp( 5, 1, 10 ) ; // 5
    auto b = std::clamp( 11, 1, 10 ) ; // 10
    auto c = std::clamp( -1, 1, 10 ) ; // 1
}

ある値をある範囲に収めることはプログラミングではよくある処理である。標準にその方法がない場合、非統一的な方法で書かれてしまう。例えば以下のように。


auto clamped_value = std::min( std::max( value, min_value ), max_value );

また、範囲版も提案されている。


std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 } ;

// { 3, 3, 3, 4, 5, 5, 5, 5, 5 } 
std::clamp_range( v.begin(), v.end(), v.begin(), 3, 5 ) ;

ちなみに、ドワンゴ社内ではclamp( min, value, max )という引数の並びを好む人もいるようだ。また、clampを関数オブジェクトを返す関数にして、clamp(min, max)(value)などという文法を好む人もいるようだ。

N4537: Adding Symmetry Between shared_ptr and weak_ptr

weak_ptrに欠けているshared_ptrの機能を追加する提案。

shared_ptr<vector<int>>のような型から、vectorのある要素へのポインターを返すweak_ptrがほしいとする。shared_ptrにはそのための機能がある。所有権を管理するポインターと、getで変えるポインターをコンストラクターの引数で別々に指定することができるのだ。

shared_ptr<int> first_elt_strong(const shared_ptr<vector<int>>& vec)
{
    return shared_ptr<int>(vec, &vec->at(0));
}

さて、戻り値に返すポインターに、それほど強い参照が欲しくない場合、戻り値の型をweak_ptrに変えることが考えられる。すると、以下のようになる。

weak_ptr<int> first_elt_strong(const shared_ptr<vector<int>>& vec)
{
    return shared_ptr<int>(vec, &vec->at(0));
}

これは動く。ただし、必要以上に非効率的である。まず、shared_ptrを作るので参照カウンターがインクリメントされる。次に、weak_ptrが作られるので、weak参照カウンターがインクリメントされる。そして、shared_ptrが破棄されるので、参照カウンターがデクリメントされる。

実に3回もの不可避なメモリアクセスが発生しているではないか。技術的には、メモリアクセスはweak参照カウンターの一回だけにできるはずである。しかし、weak_ptrのコンストラクターにはshared_ptrのコンストラクターがない。そのため、shared_ptrを経由しなければweak_ptrが作れない。

この問題を解決するために、提案ではweak_ptrにも同等のコンストラクターを追加している。

weak_ptr<int> first_elt_strong(const shared_ptr<vector<int>>& vec)
{
    return weak_ptr<int>(vec, &vec->at(0));
}

もうひとつの問題は、shared_ptrからweak_ptrを作り出すには、キャストが必要だということだ。以下の例を考えてみる。

template < ObjectType >
void f( ObjectType & obj )
{
    auto sp = obj.get_shared_ptr() ;
    auto wp = weak_ptr<ObjectType>(sp) ;
    // ...
}

このコードは、あまりジェネリックではない。もし、obj.get_shared_ptr()の返すshared_ptrが、shared_ptr<ObjectType>ではなく、shared_ptr<BaseClassOfObjectType>であるかもしれない。あるいは、std::shared_ptrではなく、独自のcustom_shared_ptrを返すかもしれない。

そもそも、このコードでは明示的に型を指定している部分は、弱体化(weakening)している部分だけである。weakeningに明示的で具体的な型を必要とするのはおかしい。

そのため、論文ではshared_ptrにweak_ptrを返すunlockメンバー関数の導入を提案している。

template < ObjectType >
void f( ObjectType & obj )
{
    auto sp = obj.get_shared_ptr() ;
    auto wp = sp.unlock() ;
    // ...
}

weak_ptrからshared_ptrを作り出す既存のメンバーとしてlockがあるので、その逆としてunlockだ。

[PDF注意] N3538: Technical Specification for C++ Extensions for Concurrency

Concurrency TS。非同期処理のための様々なライブラリの改良と追加。

N4539: C++ Standard Evolution Active Issues List
N4540: C++ Standard Evolution Completed Issues List
N4541: C++ Standard Evolution Closed Issues List

C++の新機能提案に対する既知の問題集

[PDF注意] N4542: Variant: a type-safe union (v4).

型安全unionライブラリ、variantの提案。boostのものとはvariantのネストを認めないなどで違っている。

[PDF注意] N4543: A polymorphic wrapper for all Callable objects

std::functionのコピー不可能版のstd::unique_functionの提案。

std::functionは関数オブジェクトがコピー可能であることを要求する。コピー可能ではない型は格納できない。std::unique_ptrはコピー不可能な型を格納できる。

コピー不可能であること以外は、std::functionと同等のインターフェースを持っている。std::functionでstd::unique_functionを初期化することはできる。逆はできない。

N4544: October 2015 WG21 Meeting (Kona)

2015年10月にハワイで行われる会議の案内。

ドワンゴ広告

先週の土曜日に、ドワンゴのセミナールームでTopCoderの競技プログラミングの予選、TCO15 in Tokyoが開催された。

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

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

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

2015-07-18

引越しと信用

先日、引越しを終わらせた。今回の引越しで、思うところが色々とあるので、書いてみる。

まず、今回の引越しでは、自分でシェアハウスを作ろうと試みた。そのために、色々とシェアハウス向きの物件を借りようとしたのだが、これが借りられない。理由は信用だ。

何軒かの不動産屋を回ってみて感じたこととしては、渡のつくりたいシェアハウスと、不動産屋が一般に考える不動産屋に、かなりの隔たりがあるということだ。

私の作りたいシェアハウスというのは、住人がそれぞれ一人暮らしするぐらいの賃料を払って、キッチンや風呂やリビングなどの共用部分の設備が豪華な賃貸物件に複数人で住むというものだ。

ところが、どうも不動産屋の想定するシェアハウスとは、クッソ古くてボロボロな2LDKぐらいの部屋に出稼ぎ外国人を含む10人以上が住むものらしい。

紹介される物件というものも、その賃料と地区年数なら、住人候補は全員、もっとマシな場所に一人で住むというようなものばかり。完全に認識の隔たりがあるようだ。

そして、肝心の賃貸物件が借りられない。どうやら、ある程度の規模(4LDKとか月家賃が20万円とか)の賃貸物件は、東京では個人に貸してくれないようなのだ。法人契約を求められる。しかし、私が借りようとしている物件は、事務所や社宅には不都合な間取りなのだが。

さて、仕方がないので、婚約者と二人暮らしでもしようかと思い、お互いの職場近くに2LDK程度の賃貸物件を借りようと試みた。

いくつか中を見た結果、結局、相場より高い物件はあれど、相場より安い物件というものは存在しないものだと結論した。相場より安そうにみえる物件には何らかの理由がある。

色々考えた結果、建物と部屋の維持管理に十分な金を投じている賃貸物件を借りた。多少高かったが、ちゃんと壁紙が張り替えられており、クーラーが比較的新しく、洗面台やトイレなども新しい物件だ。さらに、ベランダが温室のようにガラス張りになっていて、雨に濡れない。所有者によると防犯を考えてとのことらしいが、ガラスは簡単に割れるので、その点では疑問だ。

この賃貸物件の不満な点は、周辺に住宅と工場とオフィスビルしかなく、やや不便であるということだ。とは言え、コンビニは近いし、イトーヨーカドーも近くにあるので、とりあえず日常の買い物は問題なさそうだ。

さて、物件を借りる際には、保証会社が必須であるという。筆者は元一部上場企業(カドカワとドワンゴが合併して、持株会社カドカワドワンゴの子会社という形になったので、ドワンゴは上場廃止となったのだ。)に雇用されていて定期的な給与所得があり、貯金があり、借金もない。私は金銭的に十分に信頼できる人間である。ところが、思わぬ問題に出くわした。保証会社の審査を進めるには、携帯電話番号が必須であるという。

筆者は携帯電話を所有していない。その理由は、筆者が契約書を読む人間だからだ。およそ、携帯電話の契約書をまともに読めば、携帯電話は契約してはならないということがわかる。携帯電話を契約する人間は契約書をまともに読んでいないに違いない。そんな人間は果たして信用に値するのだろうか。

ところが、不思議なことに、この現代日本社会では、携帯電話の所有は信用に値するらしい。

これは由々しき問題だ。賃貸契約を結ぶには、金の他に、信用が必要だ。そして、この日本国では、信用は住所と携帯電話で担保されている。住所も携帯電話も持っていないものは、信用がないため賃貸契約を結べない。しかし、住所と携帯電話を同時に消失した場合、どうやって復帰するというのだろうか。

どう考えても、住所と携帯電話を同時に消失した場合、金では復帰できないように思われる。金さえあれば土地と家を買えるのではないかと思うかもしれない。しかし、携帯電話と住所がない状態で、不動産登記をどうやって行うのか。

筆者の考えた復帰方法では、どうしても他人の信用に乗るしかない。すなわち、誰か支援者を得て、支援者の住所に住民票を移す。これで住所ができるので、携帯電話を契約する。そして賃貸契約を行う。

筆者はできるだけ物を持たない生活をしている。その上で、携帯電話は不必要であるのみならず、その契約内容は危険であり、かつ、私の日々の活動を妨げる妨害装置でもある。携帯電話は一切信用できないものであり、携帯電話を所有することで信頼が生じるのは全く理解できない。

携帯電話は連絡手段であるという者がいる。しかし、この2015年には携帯電話は最適な連絡手段ではない。

仕方がないので、私のかわりに、私の婚約者が賃貸契約をすることになった。ここで保証会社の謎の要求が出てくる。なんと、先に審査すら拒否した私を、連帯保証人にすれば審査を通すというのだ。審査すら拒否するほどの信用のない私を連帯保証人にして得られる信用とはなんだろうか。おぼつかないものだ。私の連帯保証人にするならば、婚約者の親を連帯保証人から外してほしいものだ。

さて、とにかく家は確保した。引越しにはやたらとカネがかかった。私は普段から金を使う当てがないので、貯金のみ無駄に溜まっていて、支払いに問題はないのだが、この額は引越し難民がでるのも理解できる額だ。

ところで、自宅にはまだインターネット回線を引いていない。せっかくだからISPにもこだわろうかと、IIJmioひかりを契約しようと思ったのだが、なんとクレジットカード払いのみ。さて・・・これはクレジットカードを作らねばならぬのか。この分では、ネット回線を引くのは時間がかかりそうだ

そして、色々と入用なものがある。特にキッチン用品を揃えなければならない。さしあたって、レンジを買わなければならない。安いものを買うか、高いものを買うか思案している。大きな鍋も必要だ。

元Google社員、社内での給与額の公開運動について語る

Ex-Googler says she exposed company-wide pay inequality with crowdsourced spreadsheet | Fusion

EricaJoy on Twitter: "a thing bothered me yesterday and it's still bothering me today and so now i want to tell a story."

元Google社員で今はSlack社員の黒人の女であるErica Bakerが、Googleが公民権運動で有名なIda B. Wellsを取り上げたことをきっかけに、Google社内に蔓延する差別について語っている。

昔不満であることは、今もってなお不満である。そこで、ひとつ話をしようと思う。

ある日曜日、元同僚の何人かと私は退屈で、給料について社内SNSで話していた。そして、あるスプレッドシートが作られた。

我々はスプレッドシートに給料額を書き込んで、社内SNSに私のアカウントへのリンクとともに貼った。山火事のように広がっていった。

社内のいたるところで共有された。誰かがグラフを付け足して給与額の少なさを炙りだした。

私はスプレッドシートの管理をしていた(性別欄の表記統一とか、為替とか、そのへん)

さらに共有は続く。さらに人が給与額を付け足していく。物事が大きくなってきた。

私は、月曜日か火曜日に、上司に呼ばれた。上層部が不満であるという。上司は不満であるという。なぜ私はそんなことをしたのだ?

「これから何が起こるかわかっているのかね?」
何も。給料額を公開した被雇用者を不当に扱うのは違法である。
「うーむ・・・
・・・ ・・・」

ミーティングは終わった。スプレッドシートはさらに大きくなっていく。同僚は私に感謝し始めた。同僚は私に対してピアボーナス(Peer Bonus)を送り始めた。

ピアボーナスとはなにか。もし、なにかいいことをした場合、同僚はその社員にピアボーナスを付加する。ポアボーナスが付加された社員は、次の給料が150ドル上乗せされる。

この時私が学んだ重要なこととして、ピアボーナスは上司の採決が行われるということだ。私の上司は私に対するすべてのピアボーナスを却下した。

これが会社にとっていいことなのかどうかわからない。その結果が気になるところだ。ピアボーナスが一度却下されると、取り消すことはできないのだ。

ところで、これに関与していた別の同僚、白人の男(良き友人でありここで名前を挙げることはしない。彼にその気があれば自ら名乗りでるであろう)もまた、ピアボーナスを受け取っていた。

白人の男のピアボーナスは却下されなかった。私は自分が却下されたことを告げた。彼は憤った。このことをみんなに言いふらそうとした。私は差し止めた。

一部の社員がこのことを知った。元の会社の裏チャンネル(IRCで#yallknowwhoyouareだったw)で広まった。

ピアボーナスを却下するというのは聞いたことがない。そういうことが可能であることも社員は知らなかった。それが知られた時、反抗が起こった。私の言っていないことだ。

ところで、スプレッドシートはまだ続いて、広がっていった。給与帯を公開することについて人事に質問が投げられた(wwww ダメ)

大半の社員は、これがいいことであると考えた。ピアボーナスが入り続け、却下され続けた。

ピアボーナスのひとつが承認された。ほとんど却下されたあとに。なぜならば、ピアボーナスを送った社員は、その理由について極めて曖昧に書いたがために。

スプレッドシートについて言及するピアボーナスはすべて却下された。最終的に7個ぐらいあっただろうか。

上層部はいまだに不満であった。何人かの、これまで私が技術的顧問として支持してきた者達は、私に話しかけなくなった。¯\_(ツ)_/¯

私が会社を辞める前に、約5%ほどの元同僚が、スプレッドシートで給料額を共有していた。社員はスプレッドシートのデータに従って公平な給与を求め、そして得た。

天地が崩墜することはない。給与額が公開されたからと言って炎上することなどない。ただ、一部の人間の待遇が上がるだけだ。

私は会社を辞める前に、人事によってスプレッドシートが消されないように、スプレッドシートの所有権を誰かに渡した(起こり得たことだ)

私がこのことについて考えているのは、Googleが昨日、Ida B.をdoodleに載せたことについて皆が賞賛しているからだ。

Ida B. Wellsは素晴らしい。彼女はあそこまでの規模の変化をもたらした。もし、私が彼女の半分にも値するほどの女であれば、私は相当のことができる。

私はIda B. Wellsには遠く及ばないものの、たまに、人間の善のために、既存の慣習を打ち壊すことをする。

私は正義と公平を信じており、必要とあればこの2つを守るために戦う。

正義と公平のための、Google社内での戦いは、あまりうまくいかなかった。給与額の共有は一例に過ぎない。Bloggerポルノ、本名、その他多くのことがある。

もし、差別主義者(有名な差別主義者)に、帰れと言えば、クソ面白いことが起こる。差別主義者が自己保身をするためだ。明らかに。

さて、さあさあ。GoogleはIda B. Wells doodleをした。

もし、Ida Wellsがまだ生きていて、Googleで働いていたとしたら、非公開ミーティングが多数設定されて、「彼女のキャリアパス」について話されていることは保証できる。

ということだ。doodleで共有するということは、正義や公民差別についての支援をしているとはかぎらないということだ。

ドワンゴ広告

最近、アメリカでは給与額の公開という話題が熱い。同じ能力で成果を出しているのであれば同じ給与であるべきという公平感といい、人種、性別によって給料を差別しているのではないかといい、給料額を公開しない慣習自体に疑問が投げかけられている。

ドワンゴも給料額の公開に関しては同じ山の石だ。。

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

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

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

2015-07-14

C++標準化委員会の文書 2015-05 post-Lenexaのレビュー: N4521-N4530

Merge Fundamentals V1 into V2

Library Fundamentals TSのV1とV2をマージする提案。

V1とV2が分かれていた理由は、NB投票をする際の混乱を防ぐためだったそうだ。

余計に分かりづらかった気がするのだが。

N4522: std::atomic_object_fence(mo, T&&...)

atomic_object_fenceの提案。atomic_thread_fenceと似ているが、これはVariadic Templatesで任意個のリファレンスを取る。リファレンスに取ったオブジェクト以外の順序は未規定である。

N4523: constexpr std::thread::hardware_{true,false}_sharing_size

C++にキャッシュラインサイズを取得するライブラリの追加。

C++11では、std::thread::hardware_concurrency()が追加された。これは、独立して実行できるスレッドの数を返す(例えばコア数)。これは実装の際のヒントに使える。

同じ考え方で、キャッシュラインサイズをヒントとして取得したい。標準ライブラリに入れることで、移植性の高い方法でキャッシュラインサイズが取得できる。しかし、キャッシュラインそのものの定義が実装ごとに異なり移植性がない。

そのためこの提案では、目的を絞った二種類のキャッシュラインサイズ情報を取得できるようにしている。false-sharing sizeとtrue-sharing sizeだ。

false-sharingとは、2つの独立したオブジェクトが同じキャッシュライン上に乗っているがために、一方のオブジェクトに変更が加えられると、もう片方も同期のためにストールすることをいう。false-sharing sizeとは、2つのオブジェクトがfalse-sharingを避けるために取るべきオフセット値を返す。

true-sharingとは、2つのオブジェクトを合わせたメモリーフットプリントとアラインメントが同じキャッシュラインに乗るサイズを返す。

これらの値は、alignas()の中で使うのに最適である。

namespace std {
  class thread {
    // ...
  public:
    static constexpr size_t hardware_false_sharing_size = /* implementation-defined */;
    static constexpr size_t hardware_true_sharing_size = /* implementation-defined */;
    // ...
  };
}

著者はGoogle社員とnVidia社員になっている。nVidia社員が著者になるのはなかなか珍しい気がする。

N4524: Respect vector::reserve(request) Relative to Reallocation

std::vector::reserveは指定したサイズ以上のストレージを確保することが規格で規定されている。この提案は、reserveは指定したサイズを確保するように文面を変更する提案である。

初心者が期待している挙動として、サイズを指定したら、それ以上にストレージを浪費してほしくないということがまずある。また、既存のlibstdc++, libc++, MSVC2013は、指定されたサイズをそのままあロケーターに渡す実装をしている。そのため、これは単に既存の挙動を標準化するだけである。

この提案は、vector<bool>には変更を加えない。また、basic_stringにもreserveはあるものの、vectorとは性質が違うので、この提案では何もしない。

N4525: C++ Standard Library Issues Resolved Directly In Lenexa

Lenexa会議で解決された標準ライブラリの小粒な問題集。

[PDF注意] N4526: Towards improved support for games, graphics, real-time, low latency, embedded systems

「ゲーム、グラフィック、リアルタイム、低レイテンシー、組み込み系のサポートの改良に向けて」と題された壮大な論文。

内容は、N2271のEASTLを検証するものとなっている。EASTLはEAが自社内で設計して使っているSTL風のライブラリで、ゲーム用にパフォーマンスを重視した設計になっている。

[PDF注意] N4527: Working Draft, Standard for Programming Language C++

C++の最新のドラフト

N4528: Editor's Report -- Working Draft, Standard for Programming Language C++

C++ドラフトの編集者による報告書。

今回の変更点はshared_mutexか。

N4529: C++ Extensions for Library Fundamentals, Version 2, Working Draft

Library Fundamentals TSのドラフト。様々なこれまでに提案されて可決された比較的小粒なライブラリが含まれている。

N4530: Editor's Report — Library Fundamentals TS

Library Fundamentals TSドラフトの編集者の報告書。

ドワンゴ広告

KADOKAWA系列のenterbrainから出版されているニンジャスレイヤーが社内に転がっているので、最近、ニンジャスレイヤーの面白さに目覚めた。

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

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

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

2015-07-13

C++標準化委員会の文書のレビュー: N5410-N5419

N4510: Minimal incomplete type support for standard containers, revision 4

vector, list, forward_listに対して、非完全形を要素型に認める提案。

以下のようなコードが書けるようになる。

struct Node
{
    std::vector< Node > nodes ;
    // ...
} ;

クラスは定義の終了を持って完全形となるので、この場合のvectorに渡すNode型は不完全型である。つまり、sizeofが取れないなどの問題がある。しかし、不完全型をサポートする実装は可能であり、このコードは実装によって通ったり通らなかったりしていた。

上記のパターンのコードは利用価値があることから、これを認める提案。まず、最も無難なコンテナーに限って認める。

N4511: Adding [nothrow-]swappable traits (Revision 1)

<type_traits>にstd::is_swappable<T>, std::is_swappable_with<T, U>, std::is_nothrow_swappable<T>, std::is_nothrow_swappable_with<T, U>を追加する提案。

N4512: Multidimensional bounds, offset and array_view, revision 7

連続したストレージを多次元配列に見せかけるラッパーライブラリ、array_viewの提案。前回の提案N4494に比べて、細かな変更が加えられている。

[PDF注意] N4513: Technical Specification for C++ Extensions for Transactional Memory

トランザクショナルメモリーTSのドラフト

[PDF注意] N4514: Technical Specification for C++ Extensions for Transactional Memory

トランザクショナルメモリーTS。内容はドラフトと同じ。

N4515: Editor's Report: Technical Specification for C++ Extensions for Transactional Memory

トランザクショナルメモリーの編集者による変更点の報告書。

[PDF注意] N4516: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4516.pdf

ライブラリベースの型安全なunionライブラリ、variantの提案。boost.variantの機能削減版といったところだ。

なお、このvariantは空状態を許容する。理由は、別の型のオブジェクトを代入された時に、元の型のオブジェクトを破棄した後で、代入に失敗した時の状態をどうするのかと考えると、空の状態を許容する設計になったそうだ。

[PDF注意] N4517: Record of Response: National Body Comments ISO/IEC PDTS 19841

トランザクショナルメモリーTSに対するNBコメントに対する返答。

N4518: Make exception-specifications be part of the type system, version 2

例外指定を型の一部に含める提案。現状では、例外指定はポインター同士の代入を制限すると規定されている。しかし、ポインターのポインターを介せば、例外の異なる関数へのポインター型が相互に代入できてしまう。

たとえば、core issue 92は以下のようなコードを問題視している。

void (*p)() throw(int);
void (**pp)() throw() = &p;   // not currently an error

これに対し、対応はしないと結論したものの、やはりなにかおかしい。

N4519: Source-Code Information Capture

ソースファイルの情報を取得できるリフレクションライブラリの提案、__LINE__などのようなプリプロセッサーで取得していた情報が、まともな方法で取得できるようになる。

#include <experimantal/source_location>

int main()
{
    auto sl = std::experimental::source_location::current() ;

    std::cout
            << sl.line() << '\n'
            << sl.column() << '\n'
            << sl.file_name() << '\n'
            << sl.function_name() << std::endl ;
}

source_location::currentは、呼び出した場所のsource_locationオブジェクトを返すconstexpr staticメンバー関数である。

なお、source_location::currentをデフォルト実引数で呼び出した場合、呼び出し元の情報が得られる。


void logger( std::experimantal::source_location sl = std::experimental::source_location::current() )
{
    // slにはlogger関数を呼び出した元の情報が入る。
}

ドワンゴ広告

最近、ドワンゴがかなりガチな条件で3DCGエンジニアを募集しているようだ。

【新規事業】3DCGエンジニア(正社員)|募集職種一覧|採用情報|株式会社ドワンゴ

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

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

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

御岳にクライミングに行ってきた

週末に、御岳にクライミングに行ってきた。

ボルダリングを初めてはや半年、先日はトップロープも経験したので、そろそろ外壁にも挑戦してみたいと思っていた折から、同僚が何人か、週末に御岳に向かうとのころで、同行した。

朝、ホリデー快速おくたまに揺られながらThe Great Gatsbyを読みつつ御岳まで向かう。

駅を出てしばらく歩き、川に降りると、有名な忍者と呼ばれる岩に着いた。すでに先客が何人も登っている。

早速筆者も、忍者返しと呼ばれる一級課題に挑戦したが、左手の初手すら取れなかった。

疲れて木陰となっていた岩の上で寝ていたら、同僚に生贄に捧げられていた。

さて、忍者岩を後にした我々は、次にデッドエンドと呼ばれる岩に向かった。

デッドエンド自体は、当然ながら初手すら取れなかった。

デッドエンドの脇に、イギリス人のトラバースと呼ばれる二級課題がある。これに挑戦した。どうしてもヒールが離れてしまう。

初めての外岩は、何も登れていないのに疲労が激しかった。また指皮の消耗も激しい。最低一級から始まる課題が多い。また、手はともかく足の置き場がない。

それにしても気になったのは、タバコを吸うバカが多いということだ。滅んで欲しい。

2015-07-10

C++標準化委員会の文書 2015-05 post-Lenexaのレビュー: N4501-N5409

N4501: Technical Specification for C++ Extensions for Concurrency, Working Draft

同期まわりの標準ライブラリに対する拡張TS、futureの改良、latch/barrierライブラリ、アトミックスマートポインター。

[PDF注意] N4502: Proposing Standard Library Support for the C++ Detection Idiom, V2

void_tを使ったdetection idiomのためのライブラリを追加する提案の改訂版

前回のN4436と比べて、具体的な文面案が追加されているようだ。

[PDF注意] N4505: Working Draft, Technical Specification for C++ Extensions for Parallelism

並列版アルゴリズムライブラリであるParallelism TSのドラフト。既存のアルゴリズムと同じインターフェースにポリシーを指定すると並列実行してくれる。

[PDF注意] N4506: Parallelism TS Editor's Report

Parallelism TSの編集者による変更点の記述。

[PDF注意] N4507: Technical Specification for C++ Extensions for Parallelism

Parallelism TSの文面。内容なN4505と同じ。

N4508: A proposal to add shared_mutex (untimed) (Revision 4)

C++11のshared_mutexは、C++14でshared_timed_mutexに改名された。C++11のshared_mutexは、実際にはtimed lock要件を満たす必要があるためである。さて、開いたshared_mutexに、timed lockではなく、素のLockable要件のみを満たすものを追加しようという提案。

N4509: constexpr atomic<T>::is_always_lock_free

atomicの実装は、クリティカルセクションのようなロックを必要とする実装であっても、規格準拠である。これは、ロックフリーのアトミック操作を直接提供していないアーキテクチャ上でもatomicを実装可能であり、移植性の向上につながる。

しかし、プログラマーは実装がロックフリーかどうかを知って、それによって実装を切り替えたがるものだ。規格はその需要を満たすために、bool atomic<T>::is_lock_freeメンバー関数を提供している。また、ATOMIC_..._LOCK_FREEマクロもある。

問題は、実装が常にロックフリーかどうかは、コンパイル時にわからないこともある。そこで、マクロの値は、0,1,2のいずれかを取り、それぞれ、ロックフリーではない、条件付きでロックフリー、常にロックフリーという意味を持つ。

このため、常にロックフリーであることを示す、SFINAEで使いやすいconstexperメンバー関数、constexpr bool atomic<T>::is_always_lock_freeを追加しよう

ドワンゴ広告

チャーハンと名乗る同僚がおすすめするうまいチャーハンを出す悟空という店に行ってきた。名にし負うチャーハンが推薦するチャーハン屋なのだから、さぞかしうまいであろうと期待していたところ、実際にうまかった。ただし量が多すぎる。また、完全禁煙ではないので二度と行かない。

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

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

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

Hacking Teamから流出したとされるコードにブラウザーヒストリーの改変をするためとおぼしきものが発見される

国家の諜報機関に攻撃的なリモート操作ツールを売りつけている極めて非人道的な商売をしているHacking Teamから、400GBものデータが流出したという真偽不明のニュースが流れている。流出したデータの中には、FlashやSELinuxのゼロデイ脆弱性が含まれていることが発見されている。

さて、その流出したコードのなかに、ブラウザーのヒストリーを改変すると思しきコードが含まれていて話題になっている。

rcs-common/file.rb at 38290d4eab2b2c295bea021429848a3666647827 · hackedteam/rcs-common

URLを指定しなかったときのデフォルトが、["C:\\Utenti\\pippo\\pedoporno.mpg", "C:\\Utenti\\pluto\\Documenti\\childporn.avi", "C:\\secrets\\bomb_blueprints.pdf"].sampleなどとなっていて、何やらユーモアと悪意と恐怖を感じる。

そのデフォルトのプレイスホルダー的な文字列や、evidenceという単語からみて、証拠を偽造する目的のように思えてくる。

流出したデータの信頼性が怪しいので、本当のところはわからない。

2015-07-07

C++標準化委員会の文書 2015-05 post-Lenexaのレビュー: N4483-N4499

[PDF注意] N4483: Read-copy-update

Linuxカーネルで多用されているRCU(Read-Copy-Update)の解説文書。

N4484: C++ Standard Library Active Issues List
N4485: C++ Standard Library Defect Report List
N4486: C++ Standard Library Closed Issues List

標準ライブラリの既知の問題集

N4487: Constexpr lambdas

constexpr lambdaの提案。

lambda式のクロージャーオブジェクトのデータメンバー、つまりキャプチャする変数の初期化が定数式ならば、定数式のなかで利用できる。

クロージャーオブジェクトがリテラル型ならば、定数式の中で評価できる。

constexpr指定子をlambda式に記述できる。

auto f = []( int x ) constexpr { return x ; }
constexpr int x = f( 1 ) ;

constexpr指定子は省略できる。その場合、lambda式がconstexpr関数の条件を満たせば、関数呼び出し式はconstexprになる。

auto f = []( int x ) { return x ; }
constexpr int x = f( 1 ) ;

クロージャー型の関数ポインター型への変換関数はconstexprになる。

この提案は、lambda式を未評価式の中に記述することを提案していない。つまり、テンプレート仮引数のデフォルトテンプレート実引数に使ってSFINAEトリックに使うことはできない。

Clangベースの実験的実装が公開されている。

https://github.com/faisalv/clang/tree/constexpr-lambdas

N4488: Responses to PDTS comments on Transactional Memory, version 2

トランザクショナルメモリーTSに対するPDTSコメントに対する返答。

日本からは、JP1として、トランザクショナルメモリーがmath.hに対してトランザクショナルセーフを要求しているので、対応のためにパフォーマンスの低下が懸念されるとコメントを送ったが、回答は、math.hは明確に除外されているとしてリジェクトされた。

math.hが明確に除外されている文面について、日本は把握していない。

JP2として、関数のローカルstatic変数の初期化がアトミックに行われるべきだと主張したが、これもトランザクショナルセーフで定める範囲ではないとしてリジェクトされた。

N4489: WG21 2015-04-24 Telecon Minutes

4月24日に行われた電話会議の議事録。

N4490: WG21 2015-05 Lenexa Minutes

5月4日から9日にかけてLenexaで行われた会議の議事録。

[PDF注意] N4491: PL22.16 2015-05 Lenexa Minutes (Draft)

N4490のドラフトと見える。内容はほぼ同じ。

[PDF] N4492: Thoughts about C++17

Bjarne StroustrupによるC++17の考察。

ドラフト版の翻訳をすでに行っている。

本の虫: D4492: Bjarne StroustrupによるC++17の考察の翻訳

N4494: Multidimensional bounds, offset and array_view, revision 6

連続したストレージを多次元配列に見せかけるarray_viewライブラリの提案。前回からの変更点は、一部の識別子の変更や文面の変更など。

N4495: Smart Objects, an alternative approach to overloading operator dot

operator .をオーバーロードする機能の提案。N4477とは設計が違う。

N4477のoperator .は、何らかのリファレンスを返すものであった。

// N4477提案
struct Callable
{
    template < typename ... Types >
    void operator () ( Types ... args ) { }
} ;

struct X
{
    Callable c ;

    Callable & operator . ( )
    {
        return c ;   
    }
} ;

int main()
{
    X x ;
    x.foo() ;
    x.bar( 1, 2, 3 ) ;
}

何らかのリファレンスを返さなければならないということは、結構面倒な制約だ。第一、そのリファレンスが保持された場合どうするのか? その寿命がいつまで存続するのかは、operator .の実装次第だ。

// 寿命はいつまで?
auto ref = x.member ;

N4495では、operator .にコンパイラーが生成する関数オブジェクトが実引数として渡される。

たとえば、

x.some_name ;

と書いて、xにsome_nameというメンバーが存在しない場合、

x.opeator .( synthesized_function_type{} ) ;

というコードに変換される。synthesized_function_typeはコンパイラーにより生成される型で、以下と同等のものになる。

struct synthesized_function_type {
    template<class T>
    auto operator()(T&& t) -> decltype(t.some_name) noexcept(t.some_name) {
        return t.some_name;
    }
};

some_nameに対してintの値を返したい場合、これを受けるxのoperator .は、テンプレートを使って以下のように書ける。

struct some_name_t
{
    int some_name = 0 ;
} ;

struct X
{
    some_name_t data ;

    template < typename T >
    auto operator . ( T && t )
    {
        return t( data ) ;
    }

} ;

メンバー関数呼び出しの場合、実引数に渡す式は、コンパイラーが関数オブジェクトを構築する前に評価される。rvalue性は正しくforwardされる。


x.some_name( a, foo(), foo() ) ;

は、以下のように変換される。

x.operator.(synthesized_function_type{a, foo(), foo()});

コンパイラーによって生成されるsynthesized_function_typeは、以下のようになる。

struct synthesized_function_type {
    // `a' or `foo' may not be visible in that context
    // used here lexically just for demonstration purposes
    typedef decltype((a)) T0;
    typedef decltype(foo()) T1;
    typedef decltype(foo()) T2;
    T0 a0;
    T1 a1;
    T2 a2;

    template<class T>
    auto operator()(T&& t) -> decltype(t.some_name(static_cast<T0&&>(a0), static_cast<T1&&>(a1), static_cast<T2&&>(a2))) noexcept(t.some_name(static_cast<T0&&>(a0), static_cast<T1&&>(a1), static_cast<T2&&>(a2))) {
        return t.some_name(static_cast<T0&&>(a0), static_cast<T1&&>(a1), static_cast<T2&&>(a2));
    }
};

コンパイラーによって生成される関数オブジェクトに、メンバー名の文字列やメンバー関数であるかどうかを取得できるリフレクション機能をつける拡張も将来的に追加できる設計となっている。例えば、リフレクションをサポートする例として、以下のような関数オブジェクトが生成される。

struct synthesized_function_type {
    template<class T>
    auto operator()(T&& t) -> decltype(t.some_name) noexcept(t.some_name) {
        return t.some_name;
    }

    static constexpr const char* name() { return "some_name"; }
    static constexpr bool is_member_function = false;
};

うーむ・・・やりたいことはわかるのだが、この設計はもう少しなんとかならないものか。

N4496: WG21 2014-11 Urbana Minutes (revision 1)

2014年11月3日から8日にかけてUrbanaで行われた会議の議事録の改訂版とみられる。

[PDF注意] N4497: PL22.16 2014-11 Urbana Minutes (Final)

上記議事録の最終校のようなタイトル。

N4498: Variadic lock_guard (Rev. 2)

lock_guardをVariadic Templatesを使い、任意個のロックを管理できるようにしようという提案。

これまで、複数のLockable要件を満たす型をロックするのに

std::mutex m1, m2 ;

void f()
{
    std::lock( m1, m2 ) ;
    std::lock_guard< std::mutex >( m1, std::adopt_lock ) ;
    std::lock_guard< std::mutex >( m2, std::adopt_lock ) ;
}

のようなコードを書かなければならなかったが、N4498提案では、

void f()
{
    std::lock_guard< std::mutex, std::mutex >( m1, m2 ) ;
}

と書くだけでよい。

[PDF注意] N4499: Draft wording for Coroutines (Revision 2)

コルーチンのドラフト。まだまだ色々変更がありそうなので詳細に読む気にならない。

ドワンゴ広告

最近、社内で計算方法が厳密に規定されているdistributionクラスが標準ライブラリに欲しいという話がでている。デバッグ目的で全く同一の乱数列を移植性の高い方法で生成したい。C++の乱数ライブラリは、生の乱数を生成するエンジンと、乱数を目的の範囲の値に分布させるディストリビューションに分かれている。エンジンクラスの乱数の生成方法は厳密に規定されているが、ディストリビューションクラスの実装方法は規定されていない。

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

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

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

2015-07-06

ボルダリング半年

去年の12月頃から、ボルダリングを始めた。そろそろ半年はたった計算になる。

ボルダリングを始めたきっかけは、社内にボルダリングの同好会があったためだ。

最初は、30分ほどで腕が疲れて登れなくなるし、ボルダリングをした後は4日間ほど筋肉痛になっていたが、週一でボルダリングをしていると、筋肉痛になることはなくなったし、数時間続けることができるようになった。これは単純に筋力がついたのと、効率的な体の動かし方を覚えたためだろう。

かわりに、今度は肘や股関節などの関節痛になることが多くなった。これは、ボルダリングをしばらく休んで休息する以外にない。関節痛を感じたら、ボルダリングは一週間ほど控えるようにしている。

ところで去年、ボルダリングを始める直前に予備自衛官の訓練に行っていて、その体力検定で握力を図っているのだが、先日の 予備自衛官の訓練で握力を測定したところ、左右ともに10kgほど上がっていることが確認できた。

また、前腕に筋肉が着いたのか、以前より少し盛り上がっている。

さて、ボルダリングには、独特のクライミングシューズを用いる。クライミングジムではレンタルシューズを貸し出しているが、やはり自分のシューズがほしい。筆者は初めてそうそうにシューズを買った。

一足目に買ったのはスポルティバのタランチュラ(39.5)だ。履きやすく、無難な形をしていて、安いので、初心者が一足目に買うにはおすすめできる。ただ、慣れるまで足が痛かった。

三ヶ月ほどでつま先のソールが破れてしまったので、次のシューズを買うことにした。

二足目に買ったのはスポルティバのソリューション(39.5)だ。上級者がコンペなどでも使っているシューズで、値段もお高い。ただ、今のクライミングシューズの価格帯が、1万5千円から2万円ぐらいなので、差額はせいぜい5千円。どのシューズを買ってもあまり変わらない気がすると考え、買ってみた。

つま先の先端だけで極小のホールドの上に立てるし、ヒールの形状がすばらしく、ヒールフックがとてもやりやすくなった。ただ、スメアリングがしにくくなった。

基本的に素晴らしいシューズだったのだが、自分の足で登っている感覚があまり感じられない靴だった。やはりこれも3ヶ月でつま先のソールが破れてしまった。前のタランチュラも、今回のソリューションも、左のつま先のソールが破れている。おそらく左足の動きが下手で引きずるから敗れるのではないかと指摘された。

やれやれ、足の使い方が未熟であるために靴がすぐ痛むのは辛い。

さて、三足目を買わなければならない。前述の通り、クライミングシューズの価格帯は最低でも1万5千円、高くても二万円代なので、価格で選ぶ必要はない。

三足目には、足裏感覚がわかる靴を買おうと考えた。また、靴のサイズを攻めすぎずに、指の力を鍛えられるものにしたい。タランチュラもソリューションも、血が通わないくらいサイズがきつかったので、どうも足の指に力が入りにくかった。

色々と検討した結果。三足目にはスポルティバのジーニアス(40.0)を買った。このシューズにはエッジがなく、つま先の一点ではなく、面を押し付けてホールドに乗る。スメアリングもしやすい。レースアップなので着脱が煩わしくないかと懸念していたが、そんなことはなかった。靴ヒモで足の形にピッタリと合わせられるので、とても快適だ。

この靴は三ヶ月以上持ってほしいものだ。

さて、靴の次はチョークだ。手指が汗で滑ってはホールドをつかめない。そのために、クライミングではチョークを使う。チョークには液体チョークと粉チョークがある。液体チョークは強力に滑りにくくなるが、終わった後に手を洗ってもなかなか落ちない。指の皮膚へのダメージも大きいように思う。粉チョークは、すぐになくなるので、頻繁につけなければならない。

筆者は最初、マンムートの液体チョークを使っていたが、今は粉チョークを使っている。

さて、ジムでのボルダリングは、たいてい数メートルぐらいの壁を登るのだが、ロープを使って高い壁を登ることができるジムもある。ロープにはトップロープとリードとがある。

先日、ロープができるジムに行き、ビレイの講習を受けて、トップロープで登ってみた。なかなか面白い。パートナーが必要なので、それほど頻繁にできないのが残念だが、これからも機会があればロープをしたいものだ。誰か一緒に行けるロープ仲間を確保すべきか。

私が行った錦糸町のTウォールは、ロープに必要な機材がすべてレンタルできるが、ATC、カラビナ、ハーネスは、いずれ買おうと思う。

2015-07-02

C++標準化委員会の文書 2015-04-pre-Lenexaのレビュー: N4470-N4482

Variadic lock_guard

std::mutexなどのlock/unlockするオブジェクトが複数ある場合は、ロックする順番を工夫しないと、デッドロックしてしまう。そこで、標準ライブラリには、ロックする順番を実装依存の方法でデッドロックを起こさないようにしてくれるstd::lockがある。

また、標準ライブラリには、std::lock_guardという、RAIIラッパーがある。

問題はこの2つを組み合わせるのが結構ダルい。

std::mutex m1, m2 ;

void f()
{
    std::lock( m1, m2 ) ;

    std::lock_guard<std::mutex> l1( m1, std::adopt_lock ) ;
    std::lock_guard<std::mutex> l2( m2, std::adopt_lock ) ;
}

そのため、lock_guardをVariadic Templatesにして、任意個のlockを受け取れるようにする提案。

std::lock_guard< std::mutex, std::mutex > l( m1, m2 ) ;

ぜひ入るべきだ。

N4471: Template parameter deduction for constructors (Rev. 2)

クラステンプレートのコンストラクターからテンプレート実引数を推定する提案。

template < typename T >
struct S
{
    S( T ) ;
} ;

// めんどくさい
S<int> s1(0) ;
// N4471提案
S s2(0) ; // S<int>

ぜひ入って欲しい。

ただし、単純にコンストラクターから推定できない場合もある。

vector<X> v1 = { ... } ;
auto v2 = vector( v1.begin(), v1.end() ) ; // v2はvector<X>になってほしい

この場合は推定できない。提案では、typed constructorを導入するという案がある。

template<typename T, typename Alloc = std::allocator<T>> struct vector {
  // Option 1: Typed constructor in primary template only
  template <typename Iter> vector<iter::value_type>(Iter b, Iter e);
};
// Option 2: Typed constructor given globally
template<typename Iter> vector<typename iterator_traits<Iter>::value_type>(Iter b, Iter e);
template<typename Iter> vector(Iter b, Iter e) -> vector<typename iterator_traits<Iter>::value_type>

これはちょっとやり過ぎな感がある。

N4472: constexpr goto

constexpr関数の中でgotoの使用を認める提案。

現在、constexpr関数の中でgotoを使うことはできない。しかし、条件分岐やループは使うことができる。gotoが使えないのは本当に技術上の制約なのか。はた、単なる好みの問題なのか。ネストされたループから抜けるにはgotoを使うのが最も手っ取り早いし、広く使われている。gotoは本当に禁止すべきなのか。

N4473: noexcept(auto), again

noexcept(auto)復活論。

noxcept(auto)例外指定は、関数の本体が例外を投げる可能性があればnoexcept(false)に、例外を投げなければnoexcept(auto)になる。

[PDF注意] N4474:Unified Call Syntax: x.f(y) and f(x,y)

統一関数呼び出し記法の提案。

x.f(y)に対して、もし呼び出しが妥当ではない場合、f(x,y)を試みる。

p->f(y)に対して、もし呼び出しが妥当ではない場合、f(p,y)を試みる

f(x,y)に対して、もし呼び出しが妥当ではない場合で、xに対して->が定義されている場合、x->f(y)を試みる。そうでなければx.f(y)を試みる。

begin/end/swapと言った共通の処理をするのに、メンバー関数で実装されているのかフリー関数で実装されているのかがわからないため、。ジェネリックコードから使いにくいという問題を解決する。

ただし、これを真面目に考えると、"hello".puts()や2.0 .sqrt() (スペースは必要)も合法になる。

std::FILE *型の変数fpにたいして、fp->fclose()などが呼び出せるので、静的解析ツールによる補完がやりやすくなるという意見もあるが、for_eachなども補完されてしまうの、果たして便利だろうか。論文はこの懸念を載せていないが。

[Bjarneは論文をPDFで書くのをやめろ] N4475:Default comparisons (R2)

デフォルトの比較演算子を暗黙に生成する機能の提案。

クラスのデータメンバーが比較可能なとき、クラスのメンバーごとの比較を行う比較演算子を自動で生成できる機能。

ポインター型のデータメンバーがある場合は==と!=を生成しない。mutableは比較しないという、批判論文の意見は無視した形の提案となっている。

私はポインターもmutableメンバーも等しく評価されるべきだと思う。

[Bjarneは論文をPDFで書くのをさっさとやめろ ] N4476: Thoughts about Comparisons (R2)

比較演算子の自動生成に対する様々な戦略について考察している。

[BjarneはとにかくPDFをやめろ] N4477: Operator Dot (R2)

operator .をオーバーロードできるようにする提案。プロクシークラスが書けるようになる。

N4478: Networking Library Proposal (Revision 5)

ネットワークライブラリの提案。Boost.Asioが土台になっている。

N4479: Merge Fundamentals V1 into V2

提案されているライブラリ拡張のLibrary Fundamentals V2をV1にマージするという文書。NB投票の際に混乱を防ぐためにV1とV2は分割していたそうだ。

N4480: C++ Extensions for Library Fundamentals, DTS

N4481: C++ Extensions for Library Fundamentals, Version 2, Tentative Working Draft

ライブラリ拡張提案のドラフト

N4482: Some notes on executors and the Networking Library Proposal

ネットワークライブラリにおけるexecutorについて、別の論文で提案されている、軽量実行媒体との用語のすり合わせや、最新の会議での合意内容とのすり合わせ、また先行研究への言及。

ドワンゴ広告

毎週木曜日はドワンゴのボルダリング部の活動日。最近、4級が登れるようになってきた。

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

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

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

C++標準化委員会の文書 2015-04-pre-Lenexaのレビュー: N4460-N4469

N4460: LWG 2424: Atomics, mutexes and condition variables should not be trivially copyable

atomic, mutex, condition variableは、コピーができない。ただし、現行の規格の定義に従えば、trivially copyableになってしまう。

これらのクラスは、コピー代入演算子を明示的にdeleted定義されているが、それだけではtrivially copyableの条件から逃れられない。しかし、コピー代入演算子をdeleted定義すればtrivially copyableにならないと規定してしまうと、以下のようなクラスがtrivially copyableではなくなってしまう。

struct X
{
    const int val ;
} ;

このクラスは暗黙にコピー代入演算子がdeleted定義される。このクラスはtrivially copyableであるし、その挙動は変えたくない。

明示的なdeleted定義と暗黙のdeleted定義の意味を変えるという方法は、明示と暗黙の違いをできるだけなくしたいという点から、採用できない。

is_trivially_copyableとis_trivialに特殊化を記述する汚い方法はやりたくない。

論文では、規格の文面上、trivially copyableではないと記述する方法を提案している。

N4461: Static if resurrected

static ifの提案

static ifは少し前までかなり真剣に議論されていて入るかもしれないような雰囲気だったのだが、コンパイラー実装者の強い反対にあったため規格には入らなかった。

ここで提案されているstatic ifには、前回提案されていたものに比べて制約が多い。

  • ブロックスコープのみ
  • 新しいスコープを作る
  • 片方ブランチがwell-formedとなる条件部の値がどちらのブランチに対しても存在する。

GCCのRichard Smithによると、

N3329の「問題ある」部分は、

1) 新しいスコープを作らない

2) 選択されなかった方のブランチは完全に無視される(トークン列はパース可能でなくても構わない)

これは、少なくとも2つの有名なコンパイラーの実装で使われているテンプレートモデルと根本的に非互換である。

もし、static ifが(このスレで提案されているように)新しいスコープを導入し、static ifのどちらの分岐もインスタンス化可能であるならば(つまり、テンプレートのトークン列と同じ制約)、コンパイラー実装者の、俺の屍を越えて行けレベルの反対はなくなるだろう。

そのため、この論文で提案されているstatic ifは、Richard Smithの提示した制約を受け入れている。

なぜstatic ifは必要なのか。例えば、パラメーターパックを展開したいとすると、以下のようにオーバーロードを書かなければならない。

template <class T> 
void f(T&& t) 
{
    /* handle one T */
} 

template <class T, class... Rest> 
void f(T&& t, Rest&&... r) 
{
    f(t); 
    /* handle the tail */
    f(r...); // I think I have a bug here if I don't have a zero-param overload
}

これはstatic ifがあればもっと簡単に書ける。

template <class T, class... Rest> 
void f(T&& t, Rest&&... r) 
{
    /* 
      Tの処理
    */
    static_if (sizeof...(r)) {
    /*
      残りの処理
    */
        f(r...); // ゼロ引数のオーバーロードは必要ない。
    }
}

ある条件を満たすかどうかでコンパイル時に実装を切り替えるのも、とても簡単になる。現在はこう書かなければならないが、

template <class T, class... Args> 
enable_if_t<is_constructible_v<T, Args...>, unique_ptr<T>> 
make_unique(Args&&... args) 
{
    return unique_ptr<T>(new T(forward<Args>(args)...));
}  

template <class T, class... Args>  
enable_if_t<!is_constructible_v<T, Args...>, unique_ptr<T>>
make_unique(Args&&... args) 
{
    return unique_ptr<T>(new T{forward<Args>(args)...});
}

static ifがあれば、以下のように書ける。

template <class T, class... Args> 
unique_ptr<T>
make_unique(Args&&... args) 
{
    static_if (is_constructible_v<T, Args...>) {
        return unique_ptr<T>(new T(forward<Args>(args)...));
    } else {
        return unique_ptr<T>(new T{forward<Args>(args)...});
    }
}

明らかに簡単だ。

コンセプトでも問題は解決できるが、定義が分散してしまい極めて読みにくいコードになる。また著者はコンセプトとstatic ifを組み合わせるとオーバーロードを書かずにすむと主張している。

template <typename T, typename U> void f(T, U)
  requires C1<T> && (C2<U> || C3<U>)
{
    static_if (C2<U>) 
    {
    } 
    else if (C3<U>) 
    {
    }
}

なるほど、確かにこれは便利だ。

N4462: LWG 2089, Towards more perfect forwarding

何らかの簡単なコンパイル時ディスパッチの必要性を訴える論文。

make_unique, make_shared, allocator::constructといったファクトリー関数は、アグリゲートをうまく扱うことができない。

struct X { int a, b, c ; } ;

int main()
{
    // OK、アグリゲート初期化
    std::unique_ptr<X> p1( new X{1,2,3} ) ;

    // エラー、呼び出し可能なコンストラクターがない。
    auto p2 = std::make_unique<X>( 1, 2, 3 ) ;
}

これはなぜかというと、allocator::constructが、以下のようになっているためだ。

template < typename U, typename ... Args >
void allocator::construct(U * p, Args && ... args ) 
{
    return new( static_cast<void *>(p) ) T( std::forward<Args>(args)... ) ;
}

このままではアグリゲート初期化できない。しかし、一律リスト初期化{}にするのも問題だ。

LWG2089では、以下のような修正を提案している。

  • もし、is_constructible_v<TargetType, Args...>がtrueであれば、直接非リスト初期化を行う。
  • そうでなければ、初期化リストを使う。

これにより、最初の例が動くようになる。

この変更は、ライブラリでアグリゲートが使えるようになるし、実行時オーバーヘッドもないし、既存のコードもほとんど壊さないだろうし、ビルド時間もさほど増えないだろうし、実装は簡単だし、言語側での変更も必要ない。

要するに、この変更は望ましいものであって、さっさと規格入り作業を粛々と進めろとしか言う他ない。

コンパイラーベンダーが標準ライブラリにこれを実装することは慣れているので簡単だ。だがしかし、普通のユーザーが同じことをしたいとしたらどうするだろうか。

[超怖い話BEGIN] それには、非型boolテンプレート仮引数を取るクラステンプレートのstaticメンバー関数テンプレートにデリゲートし、クラステンプレートをfalseの場合に対して特殊化し、is_constructibleの結果によってディスパッチさせる[超怖い話END]

// 超怖い話の実装
template < bool >
struct construct_impl
{
    template < typename U, typename ... Args >
    static auto invoke( U * p, Args && ... args )
    {
         return new( static_cast<void *>(p) ) U( std::forward<Args>(args)... ) ;
    }
} ;


template < >
struct construct_impl<false>
{
    template < typename U, typename ... Args >
    static auto invoke( U * p, Args && ... args )
    {
         return new( static_cast<void *>(p) ) U{ std::forward<Args>(args)... } ;
    }

} ;

template < typename U, typename ... Args >
auto construct(U * p, Args && ... args ) 
{
    return construct_impl< std::is_constructible< U, Args ... >::value >::invoke( p, std::forward<Args>(args)... ) ;
}

あるいは、[超怖い話BEGIN] true_typeかfalse_typeかでタグ付けしたオーバーロードでディスパッチする[超怖い話END]

// 超怖い話の実装
template < typename U, typename ... Args >
auto construct_impl( std::true_type, U * p, Args && ... args )
{
     return new( static_cast<void *>(p) ) U( std::forward<Args>(args)... ) ;
}

template < typename U, typename ... Args >
auto construct_impl( std::false_type, U * p, Args && ... args )
{
     return new( static_cast<void *>(p) ) U{std::forward<Args>(args)... } ;
}

template < typename U, typename ... Args >
auto construct( U * p, Args && ... args )
{
    return construct_impl( typename std::is_constructible< U, Args ...>::type{}, p, std::forward<Args>(args)... ) ;
}

超怖い話は、そのままコードに落とせば動くぐらい、メタプログラミングにおけるコンパイル分岐の手法を簡潔にまとめている。さて、ユーザーも同じことをしたくなった時のために、この手法を教育しなければならないのだろうか。この手法は一般人が書けるだろうか? 書けないものはC++プログラマー失格なのだろうか?

論文筆者は、我々には何らかのコンパイル時ディスパッチを簡単にする方法が必要であると提案している。

static ifが入れば簡単に書けるようになりそうだ。

[PDF注意] N4463: IO device requirements for C++

イテレーター要件とかコンテナー要件などのように、IOデバイス要件を定める提案。

デバイスとの入出力の方法、デバイスの設定可能な項目の取得、デバイスの設定状態の取得と変更、デバイスの機能一覧の取得などが行える。

具体的にサポートするデバイスもないのにそんな要件だけ定めてなにか意味があるのだろうか。

[PDF注意] N4464: Pi-calculus syntax for C++ executors

π-calculusをC++で実現した論文。λ計算がシーケンシャルな処理をすべて記述できる計算力を持っているように、π-calculusも並列処理をすべて記述できる計算力を持っている

だが、誰が使うんだ? なんでC++標準化委員会の文書として公開されているのか理解できない。コンピューターサイエンスの理論としては興味深いものがあるだろうが、π計算の演算子をC++に持ち込んでも、まったく実用的だとは思えない。

N4465: A Module System for C++ (Revision 3)

モジュールの提案。

#includeの代替機能。プリプロセッサーはなくなるのではなくて共存する。

[PDF注意] N4466: Wording for Modules

モジュールの文面案

提案されているモジュールは、新しいキーワードとしてimportとmoduleを追加する。

ある翻訳単位をモジュールとするには、モジュール宣言を記述する必要がある。

module module-name ;

と記述する。module-nameは、識別子か、"モジュール名 . 識別子"となる。これは、std.vectorとかstd.stringとか、lib.math.random.knuthのような名前空間に似たモジュール名の分類を可能にする。

モジュールの中のエンティティを外部から使うには、import宣言しなければならない。

import std.string
import std.iostream

int main()
{
    std::string buf ;
    std::cin >> buf ;
}

モジュールとなる翻訳単位の中のエンティティは、明示的にexportしない限り外部には見えない。

module mylib

export void my_public_function() ;
void my_private_function() ;


// 囲むこともできる
export { ... }

mylibをimportすると、my_public_functionのみが見える。my_private_functionは見えない。別の翻訳単位でmy_private_functionという名前の関数を定義しても、別々の定義であり、ODR違反にならない。

module宣言で翻訳単位をモジュールにする。export宣言で外部に出したいエンティティをマーク。import宣言でモジュールを使う。というだけだ。

[PDF注意] N4468: On Quantifying Memory-Allocation Strategies

グローバルあロケーターに対してローカルなアロケーターはどのような条件でどのようなアロケーター戦略を使えばどのように効率的になるのかということを考察した論文。

なぜかドナルドの絵が引用されている。

N4469: Template Argument Type Deduction

非型テンプレートパラメーターの値を取るときに型も推定する機能を追加する提案。

現行では、以下のようなコードを書かなければならない。

template < typename T, T v > struct S ;

S< decltype(x), x > s ;

テンプレートパラメーターとして何らかの型の値を取りたいということは、まず型引数を得た上で、その型の値を取らなければならない。そのようなテンプレート使う側は、まず型を渡して、その後に値を渡さなければならない。ある値xがある場合は、decltypeでその型を得るのが最も手っ取り早い。

しかし、これは明らかに面倒だ。以下のように書きたい。

S<x> s ;

コンパイラーはxの型を推定できるのであるから、推定して欲しい。

さて、この機能をどのように実現するかについて、文法的に意見が分かれている。

最も簡単なものは、usingキーワードを使う文法だ。

// Tは推定される
template < using typename T, T v > struct S ;

このようにusing typenameと書くだけで、Tは推定される。

この文法の問題点は、仮引数と実引数の順序がずれるということだ。

template < using typename T, T v, using typename U, U w > struct S ;

S< x, y > s ;

そのため、using typenameは外に出す文法案もある。

template
    using typename T, typename U
    < T v, U w >
    struct S ;

これはテンプレート仮引数とテンプレート実引数の位置関係が対応する。

他にも、autoを使う文法案がある。

template < auto v > struct S ;

using typenameを使うほうが柔軟な型指定ができるが、autoの方が手軽だ。

どちらの文法案も競合しないので、両方入れるという案もあるそうだ。

ドワンゴ広告

社内で挙動が厳格に定義されている移植性に優れたuniform_int_distributionがほしいという声を聞いた。需要はあるのだろうか。

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

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

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

2015-06-30

C++標準化委員会の文書 2015-04-pre-Lenexaのレビュー: N4450-N4459

N4450: Variant: a typesafe union (v2)

型安全unionとして、variantライブラリの提案。

Boost.variantと似ているが、variantのネストはサポートしていない。

[PDF注意] N4451: Static reflection

静的リフレクションとして、メタプログラミングでプログラムの構造を辿れる。

論文の冒頭で、会議で上げられた懸念事項が書いてあるが、筆者も同感で、あまりにも巨大すぎる上に暴力的に強力な機能であると思う。

[PDF注意] N4452: Use cases of reflection

N4451で提案されている静的リフレクションは、あまりにも強力すぎる。初心者にそのような強力なツールを与えることは危険ではないか。という会議での懸念に対して、提案されている静的リフレクションの利用例を挙げている論文。

プログラミングにおいては、機械的な雛形コードを手で書かなければならないことがよくある。プリプロセッサーマクロやテンプレートによるメタプログラミングは、そのようなコードの記述量を抑えることに貢献しているが、限界がある。リフレクションがあれば問題を解決できる。

利用例1: ポータブルな型名

std::type_infoのnameメンバー関数の返す文字列は規格化されていない。それどころか、人間が読める文字列を返すとも、ユニークな文字列を返すとも規定されていない。文字列まで規格化された機能が必要である。さらに、nameメンバー関数はconstexpr関数ではないのでコンパイル時に使えない。また、type_infoはtypedefを考慮しないので、これまたやりにくい。

利用例2: ログ

関数の実行時にログを取るさい、関数の引数名をログ出力に含めたいことはよくある。

利用例3: シリアライゼーション

あるクラスのインスタンスをXMLやJSONやXDRのような構造化されたフォーマットで出力したい。これにはクラスごとに個別でメンバーを列挙するコードを手で書かなければならない。リフレクションがあればこのような問題は簡単に解決できる。

利用例4: Cross-cutting aspects

特定の条件を満たした関数の前後に何らかの共通処理を追加したい場合、リフレクションがあれば冗長なコードを書かずに簡単にできる。

利用例4: factory patternの実装

論文では、追加の利用例として、強力な静的リフレクションを使う利用例を挙げている。

特定のnamespace内にあるpersistent_で始まる変数名からSQLを生成。

コンパイル時にC++ソースコードを生成

デリゲートやデコレートの実装

データメンバーの配置を変える

struct foo
{
    bool b;
    char c;
    double d;
    float f;
    std::string s;
};

このようなクラスを与えると

struct rdbs_table_placeholder_foo
{
    column_placeholder<bool>::type b;
    column_placeholder<char>::type c;
    column_placeholder<double>::type d;
    column_placeholder<float>::type f;
    column_placeholder<std::string>::type s;
};

このようなコードを生成できる。

具体的にコード生成をするリフレクションを使ったコードは、論文を参照。

[PDF注意] N4453: Resumable Expressions

resumable expressionの提案。

Urbana会議以前は、コルーチンとresumable関数というやや似通った性質をもつ2つの機能が提案されていた。そして、2つの機能を統一することで合意していたのだが、スタックレスとスタックフルとはまったく別々の需要を満たすための機能であって、多少の共通項があるとはいえ、独立した機能として別々に議論すべきだということになった。これにより、スタックフルコルーチンは、純粋にライブラリ実装にして、スタックフルコルーチンをライブラリ実装できる軽いスタックレスコルーチンをコア言語に導入すべきだという方向に話が進んだ。統一の話がなくなったのであるから、awaitとかyieldなどのキーワードは不要となった。

resumable expressionsは、constexpr関数にヒントを得て設計された。

constexpr関数は、関数をconstexprであると明示的にキーワードで修飾する。そして、任意の式で呼び出すことができる。

constexpr int twice( int x ) { return x * 2 }

constexpr int a = twice( 2 ) ;
int b = twice( 4 ) ;

普通の式で使うには、関数はconstexpr関数であるかどうかを気にする必要はない。resumable expressionsもこのような設計を参考にしている。

まず、resumableキーワードを用いて、resumable関数を宣言する。

resumable void print_1_to_n( unsigned int n )
{
    for ( unsigned int i = 1 ; i <= n ; ++i )
    {
        std::cout << i << std::endl ;

        break resumable ;
    }
}

中断するところで、break resumableと記述する。

あとは、resumable式から使うだけだ。

int main()
{
    resumable auto r = print_1_to_n( 10 ) ;

    while( !r.ready() )
    {
        std::cout << "resuming ... " ;
        r.resume() ;
    }
}

resumable式は、以下の形で使う。

resumable auto r = expr ;

このときのrの型Rは実装が生成する。Rには、result_type, ready(), resume(), result()がある。

yeildやawaitなどは、resumable式を使ってライブラリで実装できる。

だいぶC++らしい小さなコア言語機能の提案だ。これは悪くなさそうだ。

N4454: SIMD Types Example: Matrix Multiplication

N4184で提案されているSIMD演算を使って行列の掛け算を実装する論文。利用例の例示として書かれた。

N4455: No Sane Compiler Would Optimize Atomics

「まともなコンパイラーはアトミックを最適化したりしない」という都市伝説は間違っていることを説いている論文。

コンパイラーはアトミックも最適化する。この論文では、最適化の例を紹介している。

コンパイラーは、プログラムをas-ifルールで最適化できる。これは、コンパイラーは、オリジナルのコードと挙動が変わらなければ、特定のアトミックを強くしたり弱くしたりできる。

最適化の例として、たとえば、アトミックの中間の値をすっ飛ばす。

void inc(std::atomic<int> *y) {
  *y += 1;
}

std::atomic<int> x;
void two() {
  inc(&x);
  inc(&x);
}

このようなコードを、最適化の結果、以下のようにしてもよい。

std::atomic<int> x;
void two() {
  x += 2;
}

他にも、x86においては、lock付きadd/subをlock付きinc/decに置き換えることも可能だ。

また、アトミックのまわりの処理も最適化の対象になる。

int x = 0;
std::atomic<int> y;
int dso() {
  x = 0;
  int z = y.load(std::memory_order_seq_cst);
  y.store(0, std::memory_order_seq_cst);
  x = 1;
  return z;
}

このコードは、以下のように最適化できる。

int x = 0;
std::atomic<int> y;
int dso() {
  // デッドstore操作の除去
  int z = y.load(std::memory_order_seq_cst);
  y.store(0, std::memory_order_seq_cst);
  x = 1;
  return z;
}

上と似ている以下のようなコードは、

int x = 0;
std::atomic<int> y;
int rlo() {
  x = 0;
  y.store(0, std::memory_order_release);
  int z = y.load(std::memory_order_acquire);
  x = 1;
  return z;
}

以下のように最適化できる(ただし、現在LLVMはこの最適化ができない)

int x = 0;
std::atomic<int> y;
int rlo() {
  // デッドstore操作の除去
  y.store(0, std::memory_order_release);
  // 冗長なloadの除去
  x = 1;
  return 0; // 保存された値がここまで到達
}

loadが除去されるのは、他のスレッドとの同期がないためだ。releaseの次にaquireがきているが、コンパイラーはstoreされた値が改変されないので、その次のloadは冗長だと判断する。

なんだかこの最適化は極めて怖い。

以下のようなコードは変換されない。

int x = 0;
std::atomic<int> y;
int no() {
  x = 0;
  y.store(0, std::memory_order_release);
  while (!y.load(std::memory_order_acquire));
  x = 1;
  return z;
}

論文は最後に、それぞれの立場に対して意見を述べている。

標準化委員会へ:これらの最適化が起こらないと仮定するな。むしろ推奨しろ。よりハードウェアに近い最適化ができる既存の方法を標準化しろ。同期と並列実行をより簡単にできて、失敗しにくいライブラリを提供しろ。

開発者へ:アセンブリを捨てろ。そんなに最適化できないし、そもそもコードを書いている時点で存在するアーキテクチャにしか対応できない。コンパイラーのパフォーマンスが期待通りでないのならばバグ報告を投げろ。標準化委員会に同期と並列実行を実現できる方法を提案しろ。ThreadSanitizerのようなツールをt受かってコード中の競合を発見しろ。

ハードウェアベンダーへ:ハードウェアの能力を示せ。

コンパイラー開発者へ:さっさと仕事にもどれ。まだ最適化できることと・・・ぶち壊れるコードは山ほどある。利用者がいいコードを書けるようにしろ。コンパイラーはアトミックの正しくない使い方を検出したならば、メッセージを吐くべきだ。

N4456: Towards improved support for games, graphics, real-time, low latency, embedded systems

N2771のEASTLの論文を考察している。現在のSTLに足りないもの、やや古い論文なので、現代ではもう意味がなくなったものなどを列挙している。

N4457: C++ Standard Core Language Active Issues
N4458: C++ Standard Core Language Defect Reports and Accepted Issues
N4459: C++ Standard Core Language Closed Issues

コア言語に対する問題集。

ドワンゴ広告

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

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

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

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

シェアハウスとタバコと暴力

以下のようにまとめられている。

「煙草の煙から自身を守るためなら暴力もやむを得ない」のか - Togetterまとめ

何を書いても火に油を注ぎ、単に第三者の余興となるだけなのだが、私(江添)の視点で書いておこうと思う。

まず、妖怪ハウスの間取りについて説明しなければならない。妖怪ハウスにはリビングがあり、その横に和室がある。私はこの和室に住んでいる。リビングと和室に面してベランダが設置してある。このリビングと和室に面したベランダは禁煙である。かつ、室内に煙草の煙が流れこむことや、室内にタバコの吸い殻や灰をばらまくのも、極めて迷惑であり常識がない行為であると同意がなされている。

妖怪ハウスには、喫煙所として定められた、別のもっと大きなベランダがある。

28日の夕方過ぎ、なぜか自室の和室が煙たいことに気がついた。臭いは窓の外からやってくるようである。見ると、リビングと和室に面したベランダでタバコを吸っている見知らぬ人間が二人いる。私はタバコを即座に中止するように、また、家から出て行くように言った。そんなところで煙を発生させる非常識な人間に家に上がることを許可したくはない。

さて、この失礼な二人は、妖怪ハウスの住人である平林の連れてきた客であることが明らかとなった。私は、何故そのような非常識な客を連れてきたのか、非常に迷惑していると平林に言った。この時、私はかなり怒っていたので、声は自然とどなり声になってしまった。平林の返答は、その語句を具体的に覚えていないが、「そう、残念だったね」などと言った極めて責任感のないものであったと記憶している。私は怒りのあまり机をけった。

この後、つかみ合いに発展した。平林に発生した結果が以下の通り。

私側としては、右目の下と首筋に引っかき傷を得た上に、メガネのフレームが曲がった(私のメガネは樹脂製ではなくチタン製なので、割れることはなかった。)

目撃者によると私から手を出したとのことだが、これは間違いで、平林から手を出してきたのだ。私は手を振りほどこうとしていただけだ。私の背の後ろから観測したので、平林の伸ばす手が見えなかったのだろう。メガネを割ったのは意図的ではなく、クビをしめられている最中になんとか身を離そうともがいた結果だ。

なぜか私が殴ったと思い込んでいる者もいるようだが、(メガネが正面から殴られて割れたように見えるからだろうか)私は殴っていない。なんとか首を絞められているのを振りほどこうとしただけだ。

ぐっちょむについて

ぐっちょむはこの場に居合わせておらず、後から私以外の観測者から話を聞いて私に論争をふっかけてきた者である。他人に受動喫煙をさせる可能性のある場合はタバコを吸わないのが当然であるべきなのだが、ぐっちょむはそれに同意していない。ぐっちょむは伝聞を元に尾ひれをつけて事実と異なることを主張するのと、同じ話題を延々とループするので、話が成立しない。ぐっちょむはドラッグをやっているという話があるので、私は関わりたくない(ドラッグを引き合いに出したのは、まともに会話が成立しないからである。)

住人の一人が警察を呼んだというのは、はるしにゃんが私にラップトップを壊されたと言いがかりをつけたことだ。私には全く身に覚えがないばかりか、その壊れたラップトップが存在するのかも知らない。「説明できないということは私が犯人だ」などという謎の論理を持ちだされても仕方がない。

今後

私に受動喫煙させる失礼な客を連れてきた挙句に、掴みかかってくる人間と同居はできないので、私は次の物件を見つけ次第妖怪ハウスを出て行く。7月中に物件を見つけたいものだ。

2015-06-29

そんなにセキュアではないお粗末なNoScriptのホワイトリスト(修正済み)

The NoScript Misnomer - Why should I trust vjs.zendcdn.net? | The Hacker Blog

「俺の環境はNoScriptを入れてるからセキュアだぜ」などと豪語する勘違い野郎に冷水を浴びせるために、デモ可能なNoScriptを迂回する方法を探していた人間が、NoScriptのお粗末なホワイトリスト指定を発見したそうだ。

NoScriptはデフォルトで、非常に有名なドメイン名(CDN、超有名Webサイト等)をホワイトリストに入れている。

しかし、このドメイン名をホワイトリストは、サブドメインもホワイトリストに入ってしまうという問題がある。もしサブドメインとページ内容を第三者が自由に作成できるようなドメインが入っていれば、信頼が破綻する。

さて、リンク先の著者は、まずホワイトリストに入っているドメインのWebサイトのXSS脆弱性を探そうと考えた。ところが、それをするまでもなく、ある重大な発見をした。

なんと、ホワイトリストに入っているドメイン名の一つ、zendcdn.netが誰にも所有されることなく空いていたのだ。

とりあえず同ドメイン名を10.69ドルで購入してJavaScriptを仕込んでみると、見事NoScriptが迂回できた。

しかし何故誰も所有していないドメイン名がホワイトリスト入りされているのか。

どうやら、ユーザーが有名なCDNをホワイトリストに追加するようNoScriptに要請したようだ。

InformAction Forums • View topic - JavaScript CDNs to add to whitelist

NoScript開発者のGiorgio Maoneに、この脆弱性について連絡を撮ったところ、彼の返事と対応は極めて迅速であり、一時間もしないうちに修正パッチがサイト上に上がり、2日後にはアップデートが全NoScriptユーザーに配布されたという。

リンク先の人間は、NoScriptユーザーはホワイトリストを確認し、自分が信頼しないドメインは取り除くべきであると書いている。

2015-06-23

C++標準化委員会の文書 2015-04 pre-Lenexaのレビュー: N4440-N4449

N4440: Feature-testing recommendations for C++

機能テストマクロの提案。C++17機能に対応するマクロが追加されている。

[PDF注意] N4441: SG5: Transactional Memory (TM) Meeting Minutes 2015-03-23 and 2015-04-06

トランザクショナルメモリーの会議の議事録。

N4442: Default argument for second parameter of std::advance (Rev. 1)

std::advanceの第二引数にデフォルト実引数として1を追加する提案。

std::advance( iter, 1 ) ;

のかわりに、

std::advance( iter ) ;

と書ける。

N4443: Introducing alias size_type for type size_t in class std::bitset (Rev. 1 )

std::bitsetにネストされた型名™size_typeを追加する提案。

他のコンテナーとあわせることで、ジェネリックなコードやポータブルなコードを書きやすくなる。

N4444: Linux-Kernel Memory Model

現行のC/C++のメモリーモデルがLinuxカーネル開発者のお気に召さなかった問題を受けて、Linuxカーネルのメモリモデルをまとめた文書。

Linuxカーネルのメモリモデルについて解説した文書。前回のN4374からの変更点はREAD_ONCE()とWRITE_ONCE()マクロの解説。

N4445: Overly attached promise

promiseに共有状態を管理するためのリソースを破棄させるメンバー関数、resetとreleaseの追加。

あるpromiseオブジェクトを使ったとする。

std::future<int> f()
{
    std::promise<int> p ;
    auto future = p.get_future() ;
    p.set_value( 42 ) ;

    // これ以降、promiseは使わない

    // 何らかの時間のかかる処理

    // promiseオブジェクトが破棄される
    return future ;
}

上記の例では、何らかの時間のかかる処理をしているあいだ、promiseオブジェクトは生きている。すると、共有状態を維持するためのリソースも破棄されないまま維持されてしまう。リソースの制約の厳しい環境では、このような不必要なリソースを早期に破棄したい需要がある。

現行規格でも、ムーブを使えばリソースの破棄は可能だ。以下のような方法でpromiseのオブジェクトpをムーブさせてリソースを開放させられる。

p = std::promise<int>{} ; // これでもよい。
std::promise<int>( std::move(p) ) ; // こちらのほうがわかりやすい

しかし、どちらも冗長でわかりにくい。N4445では、promiseから共有状態のリソースを破棄するためのメンバー関数、resetとreleaseを追加する提案をしている。

releaseは共有状態の破棄。resetは空のpromiseとswapをしたかのように働く。

N4446: The missing INVOKE related trait

ある型がある並びの引数の型で関数呼び出しできるかを調べるis_callableの提案。

より厳密に説明すると、N4169で入ったinvokeが未評価オペランドにおいて合法かどうかを確かめる。is_callableの提案。

template <class, class R = void> struct is_callable; // not defined
template <class Fn, class... ArgTypes, class R>
  struct is_callable<Fn(ArgTypes...), R>;

たとえば、is_callable< F ( A0, A1, A2 ) >::valueは、std::invoke< F, A0, A1, A2>が合法の場合にtrueを、substitutionに失敗する場合にfalseを返す。

void f( std::string, std::vector ) ;

constexpr bool b = std::is_callable_v< decltype(&f) ( std::string, std::vector) > ;

[PDF注意] N4447: From a type T, gather members name and type information, via variadic template expansion

「型Tからメンバー名と型情報をVariadic Templates展開で得る」という、なんとも説明的で実用的なタイトルの提案論文。内容として派生的リフレクション機能だ。

その提案内容も極めて実用的だ。typedef<T, C>, typename<T, C>, typeid<T, C>という文法を追加する。Tはクラス型で、Cはコンセプトか型名で、constexpr operator ()でbool値を返す。trueを返したメンバーだけが展開される。

その動作は、サンプルコードを見たほうが良い。


using namespace std;

namespace ns {
    struct X {
        int x, y;
    };
}

vector<std::string> names{ typeid<ns::X, is_member_object_pointer>... };

tuple<typename<ns::X, is_member_object_pointer>...>
    mytuple = make_tuple(typedef<ns::X, is_member_object_pointer>...);

最後の二行のコードは、コンパイラーによって以下のように変換される。

vector<string> names { "x","y" };

tuple<ns::X::int, ns::X::int>
    mytuple = make_tuple(
        &ns::some_struct::x,
        &ns::some_struct::y);

この提案は新しいキーワードを必要としないしASTコントロールも必要としないし特別なコンパイラーマジックやライブラリーも必要としない。

用途は、シリアライゼーション、メタプログラミング、型変換、イベント駆動開発。テスト駆動開発、GUIプロパティエディター、データベースオブジェクトのマッピングインターフェース、ドキュメントの自動化、コンセプトの自動チェック、コンストラクターのリフレクション。

まあ、便利だとは思うのだが、なんとも低級な機能だ。

N4448: Rounding and Overflow in C++

演算の結果の丸めとオーバーフローの挙動を規定できるライブラリの提案。

丸めモードにはすでにfenv.hがあるが、これは不十分だとしている。

丸めモードに対しては、以下の挙動が提案されている。

enum class rounding {
  all_to_neg_inf, all_to_pos_inf,
  all_to_zero, all_away_zero,
  all_to_even, all_to_odd,
  all_fastest, all_smallest,
  all_unspecified,
  tie_to_neg_inf, tie_to_pos_inf,
  tie_to_zero, tie_away_zero,
  tie_to_even, tie_to_odd,
  tie_fastest, tie_smallest,
  tie_unspecified
};

fastestは実行速度優先。smallestは誤差最小優先。

関数には、convertと、divideとrshiftが用意されている。

オーバーフローには、以下の挙動が提案されている。

enum class overflow {
  impossible, undefined, abort, exception,
  special,
  saturate, modulo_shifted, modulo_dividend, modulo_divisor, modulo_positive
};

impossible: オーバーフローは起こりえない。これを指定したプログラムは厳格な検証によりオーバーフローがー起こりえないことを証明すること。

undefined: オーバーフローはまれにしか起こらないので考えなくてよい。

abort: オーバーフローが起きたらabortする。検出が必要。

exception: オーバーフローが起きたら例外を投げる。検出が必要。

special: オーバーフローが起きたら特別な値を返す(IEE浮動小数点数など)

saturate: オーバーフローが起きたら妥当な範囲の値で最も近いものを返す。

オーバーフローを指定できる関数には、convertの他に、limit( lower, upper value )とその派生版と、lshiftが提案されている。

最後に、丸めとオーバーフローを両方取るconvertとbshiftが提案されている。

N4449: Message Digest Library for C++

暗号に使える強度を持ったハッシュ関数ライブラリの提案。

「設計はPythonのhashlibモジュールから恥ずかしげもなくパクった」

まだ文面が不完全だが、Pythonのhashlib風のインターフェースになっている。

ドワンゴ広告

どうやら弊社では、自社から出た最新の参考書を自腹で買う社員が多いようだ。他ならぬKnuth本ならば仕方あるまい。しかし、ご存命のうちに完成するのだろうか。

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

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

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

江添ボドゲ会@7月

江添ボドゲ会@7月 - connpass

7月4日の土曜日に、野方でボードゲーム会を行う。参加費千円。今回はカレー。

7月には引越しを終えて新居でボドゲ会ができるかと見込んでいたのが、どうやらまだ時間がかかりそうなので、今回も野方の妖怪ハウスで行う。

来月こそは引越しをしたい。

2015-06-22

C++標準化委員会の文書 2015-04 pre-Lenexaのレビュー: N4430-N4439

N4430: Core Issue 1776: Replacement of class objects containing reference members

Core Issues 1776を解決するための文面変更。

ストレージに構築されたクラスオブジェクトを破棄して、そのストレージ上にまたクラスを構築するとき、もとのクラスにconstなリファレンスのデータメンバーがあった際などに、規格の範囲内でoptionalが実装できない制限を緩和する。

またこの文面では、std::launderというアドレスロンダリング用の関数テンプレートが追加されている。

[PDF注意] N4431: Working Draft, Standard for Programming Language C++

最新のC++標準規格のドラフト

N4432: Editor's Report -- Working Draft, Standard for Programming Language C++

N4431に加えられた変更点。今回は大きな変更はない。

N4433: Flexible static_assert messages

static_assertの警告メッセージに、文字列リテラルだけではなく、文脈上const char*, const wchar_t*, const char16_t*, const char32_t*に変換できる定数式を許可しようというもの。

const char * msg = "hello" ;
static_assert( false, msg ) ;

これは現在提案中のコンパイル時文字列ライブラリと組み合わせると強力に使える。

template < typename ErrorCode, typename Message
constexpr auto msg( ErrorCode code, Message message )
{
    return "My Lib: error code "S + code + ": "S + message ;
}

static_assert( sizeof(int) == 4, msg( "001"S, "This library assumes that sizeof(int) is 4." ) ) ;

[PDF注意] N4434: Tweaks to Streamline Concepts Lite Syntax

GCCのコンセプトブランチで、N4377で提案されているコンセプトを実装してみた経験から、現在の提案に対する改良の提案。

boolは冗長。

コンセプトは常に真偽値を返す。conceptキーワードはある。なぜboolキーワードが必要なのか。

template < typename T >
concept bool C() { return ... ; }

template < typename T >
concept bool C = ... ;

明らかにboolキーワードは冗長なので、省略できるようにすることを提案している。

関数コンセプトと変数コンセプトは冗長

コンセプトには、変数コンセプトと関数コンセプトが存在する。これらは定義する文法が異なる他にも、requires-clauseでの呼び出し方も異なる

template &lt; typename T &gt;
concept bool C1() { return ... ; }

template &lt; typename T &gt;
concept bool C2 = ... ;

template < typename T >
requires C1<T>() && C2<T> ;
void f( T ) ;

関数コンセプトを利用するには、冗長な()を余計に記述しなければならない。かつ、コンセプトの利用者は、あるコンセプトが変数コンセプトなのか関数コンセプトなのか把握していなければならない。そんなことはどうでもいいことであり人間が把握すべきことではない。

そもそも、コンセプトに2種類の文法が存在するのは、歴史的なアーティファクトに過ぎない。まだ変数テンプレートがなかった時代に関数コンセプトのみがあり変数テンプレートができたためにその文法を流用した変数コンセプトができたのだ。今の提案では、変数コンセプトのみを使っているので、関数コンセプトは不要だ。そもそも、関数コンセプトは利用時に冗長な()を必要とするのみならず、定義時にも冗長な()やreturnを必要とする。

変数コンセプトに統一することを提案してる。

コンセプトがコンセプト以外の場所で評価できないのは冗長なコードを生む。

ある型TがあるコンセプトCを満たすかどうかを調べるにはどうするか。現行のコンセプトでは、コンセプトはrequires-clauseでしか使えないとされている。すると、ある型がコンセプトを満たすかどうかのbool値を取得するためには、コンセプトそれぞれに対して、以下のような冗長で機械的なラッパーを書かなければならない。

template< class T >
constexpr bool
satisfies_C( ) { return false; }
template< C T > // equivalent to requires C<T> for class T
constexpr bool
satisfies_C( ) { return true; }

こんなコードを書かせるのは明らかに間違っている。コンセプトはbool値を期待するあらゆる文脈で使えるようにすべきだという提案。

どれも正しいように思われる。

[PDF注意] N4435: Proposing Contract Attributes

属性を使った契約プログラミングをサポートする文法の提案。precondition, postcondition, invariantsをサポート。

契約プログラミングに関する提案論文は多数出ているが、実際の文法を考察した提案論文は少ない。この提案論文では、C++11に追加された属性を使った文法を考察している。

まず、公式の機能に属性を使うのが正しいのかという議論がある。アライメント指定やoverrideは、属性でサポートすべきではないとして、キーワードが与えられた。N2761では、属性を使うべき状況として、「型システムに影響を与えず、属性の有無によってプログラムの意味に影響を与えない」ことを要件として提案している。契約は型の一部ではない。規格準拠の実装は、契約を単に受理だけして無視してもよいものである。これを考えると、契約を属性でサポートするのは理にかなっている。

提案では、preconditionとして、[[ pre: expr ]]、postconditionとして、[[ post: expr ]]という文法を提案している。これらはどちらも、関数、関数テンプレート、メンバー関数、メンバー関数テンプレートに付与することができる。

属性を記述する箇所として、論文は、現在の規格には存在しない、関数の宣言の後に記述できるように属性を拡張すべきだという提案をしている。

template< class FwdIterator, class T >
bool
std::binary_search( FwdIterator first, FwdIterator last, T const& value)
[[ pre:(std::is_sorted(first, last)) ]];

この理由は、関数の引数名を契約チェック式のスコープに含めたいためである。

postconditionの例は以下の通り。

template< class RandomAccessIterator >
void
std::sort( RandomAccessIterator first, RandomAccessIterator last );
[[ post:(std::is_sorted(first, last)) ]];

postconditionは、関数がreturn以外の方法(例外、longjmp等)で戻った場合はチェックされない。

この提案では、他の契約プログラミング提案と違い、invariantsを含んでいる。invariantsは、preconditionとpostconditionを組み合わせた効果がある。これは、[[ inv : expr ]]という文法で記述できる。

invariantsは、関数の他に、クラスとループ構文と変数に指定できる。

クラスに付与した場合、クラスのpublicとprotectedなメンバー関数に契約チェックがかかる。privateなメンバーにはかからない。また、コンストラクターには、postconditionチェックのみがされる。デストラクターには、preconditionチェックのみがされる。これは、コンストラクターは未初期化の状態から値を設定するものであり、デストラクターは実行後に値を不定な状態にするものだからである。

ループ構文にinvariantsを付与した場合、ループの実行毎に契約チェックが入る。

変数にinvariantsを付与した場合、変数の構築時と変更時に契約チェックが入る。

[PDF注意] N4436: Proposing Standard Library Support for the C++ Detection Idiom

N3911で追加されたvoid_tを利用したdetection idiomのためのライブラリの提案。

N3911では、以下のようなエイリアステンプレートvoid_tを標準ライブラリに追加した。

template < typename ... >
using void_t = void ;

void_tは、任意個の型引数を受け取って、必ずvoid型を返す。このような単純なものに何の価値があるのかというと、SFINAEで活用できる。

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

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

このように、void_tには任意個の型を渡せるので、SFINAEの文脈で使ってやれば、ネストされた形名typeを持っているかどうかでコンパイル時分岐ができる。

decltypeを使えば、式を書くことも可能だ。

template < typename, typename = void_t<> >
struct is_pre_incrementable
    : std::false_type { } ;

template < typename T >
struct is_pre_incrementable< T, void_t< decltype(++std::declval<T &>()) > >
    : std::true_type { } ;

論文では、このような用法をdetection idiomと名づけている。

Jonathan Wakelyによれば、libstdc++で_GLIBCXX_HAS_NESTED_TYPEマクロをvoid_tを使った上記の実装に置き換えたところ、従来の実装に比べて、コンパイラーフロントエンドのメモリ消費量とコンパイル時間が向上したとの報告がある。

現在、規格の文面がpartial specializationでSFINAEが働くかについて曖昧であるという議論が起こっているが、SFINAEが働く方向に意見が向かっている。

論文筆者はdetection idiomを使って既存の標準ライブラリを再実装する実験を行った。この結果、冗長なコードの重複が至るところでみられた。論文筆者は、再実装の過程で、この冗長なコードを隠匿する方法を発見した。論文はその手法をメタ関数コールバック(metafunction callback)と名づけている。そのフレームワークを標準ライブラリに提案している。

このライブラリを使えば、上のhas_typeとis_pre_incrementableは以下のように書ける。

// メタ関数コールバック
template < typename T >
using has_type_op = typename T::type ;

template < typename T >
constexpr bool has_type_v = is_detected_v< has_type_op, T >


// メタ関数コールバック
template < typename T >
using is_pre_incrementable_op = decltype( ++std::declval<T &>() ) ;

template < typename T >
constexpr bool is_pre_incrementable =is_detected_v< is_pre_incrementable_op, T > ;

メタ関数コールバックは、テンプレートである。テンプレートをそのまま渡すと、中でテンプレート実引数を渡す。もしsubstitutionに失敗するか成功するかが実行結果だ。戻り値は、失敗したという情報か、成功した場合のテンプレートの型だ。成功した場合、is_detectedの::valueはtrueになり、::typeはメタ関数コールバックにテンプレート実引数を渡した型になる。失敗した場合、::valueはfalseとなり、::typeはvoid型になる。。メタ関数コールバックにはエイリアステンプレートを使うのが一般的になるだろう。

上記の実装は、変数テンプレートを使っている。クラステンプレートで従来のメタ関数を実装するには、std::true_typeかstd::false_typeを返す必要がある。これには、detected_orが使える。これは、失敗した場合の型を指定できる。

template < typename T, typename = typename T::type >
using has_type_op = std::true_type ;

template < typename T >
struct has_type :
     detected_or_t< std::false_type, has_type_op, T > 
{ } ;

他には、メタ関数コールバックのsubstitutionに成功し、かつ、型が指定した型かどうかを返すis_detected_exactと、それに似ているが、型が指定した型に変換可能かどうかを返すis_detected_convertibleが提案されている。

また、voidもメタ関数コールバックの戻り値としてふさわしい場合に使える。nonesuchという型が提案されている。

これはいいライブラリだ。標準に入るべきである。

[PDF注意] N4437: Conditionally-supported Special Math Functions, v3

TR1に存在した数学関数を、条件付きサポートとして規格に入れる提案。実装しなくても規格準拠である。

TR1はC++11に追加されたが、数学関数だけは入らなかった。その理由は、これらの関数の実装をすべてのC++コンパイラーベンダーに強いるのは負担であるし、それに、「どうせ数学関数が実装されていなくても、ユーザーはうちの会社にカチこんできたりしない」からであった。

この提案で<cmath>に追加される関数は、acosh, asinh, atanh, cbrt, copysign, erf, erfc, exp2, expm1, fdim, fma, fmax, fmin, hypot, ilogb, lgamma, llrint, llround, log1p, log2, logb, lrint, lround, nan, nearbyint, nextafter, nexttoward, remainder, remquo, rint, round, scalbln, scanbn, tgamma, truncと、末尾がfのfloat版と、末尾がlのlong double版。また、マクロと<fenv.h>(浮動小数点演算の例外状態を取得できるライブラリ)も入る。

[PDF注意] N4438: Industrial Experience with Transactional Memory at Wyatt Technologies.

Wyatt Technologies社によるトランザクショナルメモリーの知見。

トランザクショナルメモリーは長年研究されているが、現場で使用した知見はなかなかない。Wyatt Technologies社は、Haskellを参考にしたトランザクショナルメモリーをライブラリで実装して、現場の製品に使用した。

トランザクションの中で、すでに他のトランザクションが行われたかどうかをチェックできる。他のトランザクションが行われた場合、即座にトランザクションは再実行される。

短いトランザクションが連続的に発生するため、長いトランザクションがいつまでたってもコミットできない飢餓状態という問題がある。実装では、許容可能なコンフリクト数を設定可能にしている。許容限度に達した場合、トランザクションの実行を諦めて例外を投げるか、実行ロックをかけるかが選べる。実行ロックとは、そのトランザクションがコミットされるまで、他のトランザクションを許さない排他的なロックである。これにより飢餓状態を解消する。

このトランザクショナルメモリーの実装は、トランザクションをネストできる。ネストできない場合、すでにトランザクションの中であるかどうかを把握しなければならない。Haskellではネストできないので、この点が違っている。

論文に書かれている内容では、トランザクションをネストしたり、トランザクションの中からトランザクションの状態をみたり操作したりできる実用本位の機能が多い。

論文は、現場にトランザクショナルメモリーを導入した明示的にロックを使わないコードの結果は上々であったと報告している。トランザクショナルメモリーを現場に持ち込むことの問題として、新たに雇用する人間にトランザクショナルメモリーの経験のある人材がいないということがあるが、新しく雇ったプログラマーもすぐに覚えることができたと報告している。

実装ではひとつのグローバルなmutexを使ったそうだ。

結論として、トランザクショナルメモリーの経験は素晴らしかった。TMの理論上の問題点は、飢餓状態と副作用にあるが、どちらの問題も対処は難しくなかった。副作用の問題を型システムで対処できれば理想だが、ライブラリベースの実装では無理だ。ロックベースのプログラミングのために必要なコードが複雑になるコストを考えれば、副作用の問題は十分に許容できる範囲だ。

また、retry(トランザクションの中で呼び出して、ある値が変更されるまでスリープする機能)と、after(トランザクションの中で呼び出して、コミット後に行われる副作用を登録する)機能を多用したので、この機能なしではトランザクショナルメモリーは使いづらいとしている。

また、この報告の例は、極めてトランザクショナルメモリーに優しい環境であった。厳しいパフォーマンス上の制約もないし、リアルタイム性も必要ないし、ゲームにおける高フレームレートのような要件もないし、株取引でもない。パフォーマンスが必要な部分は装置から入力を読みだす部分だけで、そこはトランザクショナルメモリーではなくてロックフリーキューを用いた。

[PDF注意] N4439: Light-Weight Execution Agents Revision 3

スレッドよりも軽い、制約の多い、実行媒体(Execution Agent)のセマンティクスを定義している論文。

実行媒体とは、スレッドの他にも、SIMDやGPGPUのようなもっと制約の多い実行媒体を想定している。

ドワンゴ広告

先週、ボーナスがでたので、弊社のお金ない勢が銀座のさくら水産でオフ会(予算600円程度)を行った。そこでは浪費しすぎて給与が右から左にクレジットカードの支払いで消えていく社員たちが卵かけご飯を食べながらお金ない自慢をしあっていた。

ところで、同日同時刻に、弊社のお金ある勢もザギンのシースー屋(ただし予算1000円程度)でオフ会を行ったそうだ。そこで出た結論とは、資産を即座に3倍に増やしたいのであれば、博打しかないとのことだそうだ。

どうやら、弊社のお金ある勢とお金ない勢は、給与額よりは浪費癖で決まるようだ。

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

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

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

2015-06-21

x86のmov命令はチューリング完全

世の中には様々なチューリング完全なシステムがある。

本の虫: うっかりチューリング完全になっちゃったもの

x86のMMUはチューリング完全である。

BGP(Border Gateway Protocol)はチューリング完全である。

http://vanbever.eu/pdfs/vanbever_turing_icnp_2013.pdf

さて、x86の命令セットは極めて複雑で冗長であることが知られている。なんと、mov命令はチューリング完全であるそうだ。

http://www.cl.cam.ac.uk/~sd601/papers/mov.pdf

もちろん、mov命令でメモリ上に任意のコードを書いて実行させればチューリング完全になるが、論文ではそのようなコード生成や自己書き換えによるイカサマは行っていない。また、アドレスモードもたいていのRISCにあるようなものしか使っていないという。

x86のmov命令だけを使った後、無条件jumpで先頭に戻るループを実行することで、チューリング完全になるそうだ。

レジスターに入っている2つのアドレスA, Bが正しいかどうかは、アドレスAにある値をストアして、その後にアドレスBに別の値をストアして、そしてアドレスAの値をみると、AとBが等しいかどうかがわかる。レジスターRiの値にアドレスA入っていて、レジスターRjの値にアドレスBが入っている場合、レジスターRiとレジスターRjが等しいかどうかは、以下のようにしてわかる。

mov [Ri], 0
mov [Rj], 1
mov Rk , [Ri]

このコードはアドレスの指し示すメモリ内容を破壊するが、このアドレスはシンボル用に確保しているものなので問題はない。

比較の結果を0か1で得ることによって、Rkを使って2要素が入ったテーブルを参照することによって、2つのアドレスから選択をすることができる。レジスターNにアドレスNが入っていて、レジスターRi, Rjに選択される2つのアドレスが入っていて、Rkに比較の結果が0か1で入っている場合、以下のようにしてRi, Rjのどちらかのアドレスを選択してRlに入れることができる。

mov [N], Ri
mov [N+1], Rj
mov Rl , [N + Rk ]

この論文を元にした、MOV命令のみを使うコードを生成するコンパイラー、xoreaxeaxeax/movfuscatorがGitHubで公開されている。これはBrainfuckコンパイラーだが、BFBASICを併用することで、BASICからBrainfuckに変換できるので、BASICからmov命令(と末尾の銭湯に戻る無条件jump)のみのコードを生成するとしている。

なお、将来的にはCコンパイラーを実装するとしている。

2015-06-16

予備自衛官の訓練に出頭した

12日から16日までの5日間、予備自衛官の訓練のために朝霞駐屯地に出頭していた。5日間ネットから姿を消したので、何故か私の死亡説が流されていたようだ。

出頭して気がついたのだが、もう予備自衛官になって5年たった。もうそんなになるのかと、少し驚いた。

筆者が予備自衛官であることを人に話すと、最もうらやましがられるのは、銃を撃てることである。。筆者は銃にあまり興味はないのだが、とある人は銃を撃つために毎年のように海外に旅行しているそうだ。曰く、「銃を撃ってそのうえ金がもらえるとはなんといい身分だ」と。今回の射撃は、あまりいい成績ではなかった。

そういえば、今回の訓練の時に気がついたのだが、自衛隊の駐屯地は、筆者の知る限り、東京で唯一のまともな飯が食える場所である。[参考:本当に東京の飯はまずい]

ところで、去年の秋にも訓練に参加したので、今回は半年ぶりになる。この半年間、ボルダリングをしていた成果なのか、10kgほど握力が上がっていた。

来年はいつ参加しようか。

2015-06-11

Duqu 2.0

世間はKaspersky Lab内にStuxnetやDuquの系譜である発展版のマルウェアが仕掛けられたニュースで持ちきりだ。

The Mystery of Duqu 2.0: a sophisticated cyberespionage actor returns - Securelist

Duqu 2.0: Reemergence of an aggressive cyberespionage threat | Symantec Connect Community

Duqu2.0はStuxnetやDuquと共通のコードがみられ、出所が同じであると推測されている。またその規模から、(アメリカ合衆国かイスラエル)国家政府の支援を受けていると推測されている。

Kaspersky Lab内に仕掛けられ、Kaspersky Labによって発見されてDuqu 2.0と命名されたこのマルウェアは、Windowsの作成当時のゼロデイ脆弱性を利用して、カーネルメモリ内のみに常駐し、ストレージ上に痕跡を残さないことで、検出を難しくしているという。

創始者のKaspersky本人は、Forbesの寄稿で、セキュリティ研究会社を狙うのは割に合わないと書いている。

Why Hacking Kaspersky Lab Was A Silly Thing To Do

曰く、そもそも連中はうちに侵入して何をしたいのだ? うちの製品のソースコードとかノウハウを盗みたいのか? しかし、日進月歩で技術革新が進むこの業界で、今この瞬間の技術情報を盗んでも無意味だ。そもそも、うちは商業企業である。うちは政府とも契約を結んでいるし、国家機密に関わるような場所に納品する際にはソースコードの提出だってしている。技術情報が欲しければ普通に顧客としてくればいいではないか。国家犯罪を暴いているうちに幼稚なエゴでもって仕返しがしたかったのか? そのために何百万ドルもの血税を無駄にしているのか。意味がわからない。と。

しかし、アメリカ合衆国かイスラエル国家の支援を受けた団体が、ロシア国家の支援を受けた企業を攻撃するのはなかなかわかりやすい構図ではある。

2015-06-09

C++標準化委員会: 2015-04 pre-Lenexaのレビュー: N4420-N4429

[PDF注意] N4420: Defining Test Code

C++の型システムにテストを追加する提案。

テストは重要である。C++標準はテストをサポートする機能を提供していない。そのため、C++プログラムはサードパーティのマクロ満載のお互いに非互換なテスト用フレームワークを使わなければならない。

この提案は、テストコードと非テストコードをプログラム中で明確に分断するための機能をテスト修飾子を提案している。

void f() test ; // テスト用コード

void g() test
{
    f() ; // OK
}

void h()
{
    f() ; // ill-formed
}

テスト修飾された関数やクラスは、非テスト修飾されたコードから使うことはできない。

N4421: C++ Standard Evolution Active Issues List

N4422: C++ Standard Evolution Completed Issues List

N4423: C++ Standard Evolution Closed Issues List

C++の新機能提案に対する既存の問題、解決済みの問題、却下された問題。

N4424: Inline Variables

inline変数の提案。

以下のようなコードを含むライブラリーがあるとする。

// library.h
struct X
{
    static int data ;
} ;

このライブラリーはヘッダーのみで使えることを想定した設計にしたい。さて、このstaticデータメンバーをどこかの翻訳単位で定義しなければならない。ではどこで定義すればいいのだろうか。

これを解決するには、inline関数がstaticストレージ上の変数へのリファレンスを返せばよい。

namespace detail {
    int & get_data()
    {
        static int data ;
        return data ;
    }
}

これは動くが、余計な関数をひとつ書かなければならないし、変数を使うときに冗長な関数呼び出し式を書かなければならない。

N4424提案は、変数をinline宣言することで、プログラム中で共通の実体を指すようにしてくれるものだ。

// library.h
struct X
{
    // クラス外に定義を書く必要はない
    static inline int data ;
} ;

以前提案されていたN4147は、inline変数というよりは、inline式とも言うべきもので、初期化子の式が、その副作用も含めて、変数を使った場所で評価されるというものだった。今回のN4424提案はどこかの翻訳単位に定義を書かずともプログラム中で共通の実体を指すという目的を限定したものになっている。

[PDF注意] N4425: Generalized Dynamic Assumptions

コンパイラーは最適化のために様々な情報を必要とするが、そのような情報は外部の環境に依存していて、コード中から取得できないことがある。もし、プログラマーがそのような乗法をコンパイラーへのヒントとして記述することができれば、コンパイラーはよりよく最適化ができる可能性がある。この提案は、そのような前提条件を記述できるコア言語機能を追加する提案である。

すでに、既存のC++コンパイラーで、コンパイラーに前提条件のヒントを与える独自拡張を提供しているものがある。

MSVCは__assume(expression)というintrinsicを提供している。ここに書かれた式はtrueとなるとみなされる。コンパイラーはこの情報を使って最適化ができる。式は評価されない。

IntelのC++コンパイラーも__assumeに加えて、__assume_alignedを提供している。これはポインターのアライメントの保証を記述するものである。

IBMのXLコンパイラーは__alignxというポインターのアライメント保証を指定するための機能を提供している。

Clangは__builtin_assumeと__builtin_assume_alignedというintrinsicを提供している。また、MSVC互換モードの場合、__assumeも受け付ける。

GCCは__builtin_unreachableと__builtin_assume_alignedを提供している。

提案されている文法は、既存のtrue/falseキーワードを再利用するものだ。

true(expression)は、オペランドの式がtrueと評価されることを保証する。false(expression)は、式がfalseと評価されることを保証する。式は実際には評価されない。


true( ++i ) ; // 式は実際には評価されないので、iはインクリメントされない。

true( i == 5 ) ; // コンパイラーはiは5と等しいとみなしてよい

true( false ) ; // この文には到達しない(コンパイラーはこの文を含むコードパスを除去してよい)

false( i < 2 ) ; // iは2未満にならない

void foo( int i )
{
    true( i > 6 ) ; // iは6より大きい保証

    // この分岐はコンパイル時に評価できるし、除去できる
    if ( i < 3 )
    {
        // ...
    }
}

また提案では、alingof演算子を拡張して、true/false演算子の中で使えるようにしている。

void bar( float * q, const float * p, int n, int m )
{
    true( alignof(p) == 16 && alignof(q) == 16 ) ;
    true( m % 16 == 0 ) ;


    // mは16の倍数であることが保証されているので、
    // コンパイラーは実行時のチェックなしに、
    // このループを余さず展開したりベクトル化したりできる
    for * int i = 0 ; i < n ; ++i )
    {
        q[i] = p[i] + p[i+m] ;
    }
}

契約プログラミングをより低級にした感じだ。

N4426: Adding [nothrow-]swappable traits

std::is_nothrow_swappable<T>を追加する提案。

加えて、この提案では、std::is_swappable<T>, std::is_swappable_with<T, U>, std::is_nothrow_swappable_with<T, U>も追加する。

[PDF注意] N4427: Agenda and Meeting Notice for WG21 Pre-Lenexa Telecon Meeting

電話会議の予定表

[PDF注意] N4428: Type Property Queries (rev 4)

静的リフレクション機能として、enum型とクラス型の情報を取得できるstd::enum_tratisとstd::class_traitsの提案。

enum_traitsは、テンプレートに渡したenum型の列挙子の識別子と値を取得できる。

利用例

template < typename T,  std::size_t I >
int print( )
{
    std::cout << std::enum_traits<T>::enumerators::identifier << '\n'
        << std::enum_traits<T>::enumerators::value << std::endl ;
    return 0 ;
} 

template < typename ... dummy >
void expand( dummy ... ) { } 


template < typename T, std::size_t ... I >
void print_enumerators_impl( std::index_sequence< I ... > )
{
    // 引数の評価順序を固定しようというN4228提案が可決されることを信じている
    expand( print< T,  I > ( ) ... ) ;
}

template < typename T,
    typename Indices = std::make_index_sequence< std::enum_traits<T>::enumerators::size > >
void print_enumerators( )
{
    print_enumerators_impl<T>( Indices() ) ;   
}

class_traitsについて詳しくは論文を参照してもらうとして、提案では基本クラスの型とvirtual基本クラスかどうか、メンバーの識別子とポインター、ネストされた形の識別子と型の一覧を取得できる。取得できるのはpublicなメンバーのみ。

このようなtraitsにしておけば、将来の拡張は容易いとしている。

また論文は、将来の拡張として、reflectidというキーワードを提案している。これは、reflectid(E)のように使う。オペランドに式を与えると、decltypeのように、式を評価した結果の型を使う。reflectid(E)のEがenum型の場合、結果はenum_traits<E>型になる。reflectid(C)のCがクラス型の場合、結果はclass_traits<C>になる。

reflectidが必要な理由は、アクセス指定に対応するためだ。reflectidが導入されれば、reflectidが使われた文脈に応じた情報を列挙したclass_traitsが得られる。また、名前空間はテンプレートパラメーターで渡す方法がないため、reflectidのようなコア言語でのサポートが必要だ。テンプレートもテンプレートに渡すよりは、reflectidが欲しい。

Clangベースの実験的実装が公開されている。

ChristianKaeser/clang-reflection

N4429: Rewording inheriting constructors (core issue 1941 et al)

継承コンストラクターの挙動を変更する提案。継承コンストラクターはusing宣言の文法を使うが、挙動が異なる。これまで、派生先でコンストラクターを生成して、基本クラスのコンストラクターにデリゲートするような定義をされていた。これにより、using宣言とは違った挙動が生じてしまう。

提案では、継承コンストラクターの挙動を、派生先クラスが基本クラスのコンストラクターを本当に継承したかのように定義する変更を提案している。これにより破壊的変更もあるが、挙動の不一致がなくなり、より自然になる。

具体的な例は論文を参照してもらうとして、様々な例が上げられている。

よい変更だと思う。

ドワンゴ広告

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

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

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

2015-06-07

江添ボドゲ会@6月を開催した

江添ボドゲ会@6月 - connpass

江添ボドゲ会@6月を開催した。

今回は、新たなボドゲとして、Splendorとコヨーテと犯人は踊るを仕入れた。

今回の参加者は8人だった。前回は20人近い参加者が来たが、今回は少しおとなしかった。

今回の料理はカレーにした。カレーを作ったのは久しぶりかもしれない。

今回、ウー・ウェンの切菜刀 WN155というものを買ってみた。自分の包丁が欲しくていろいろ調べた結果、これが最も手頃で使いやすそうだと判断したためだ。実際に使ってみると、これがとても使いやすかった。鋼の両側をステンレスで挟んだ三重構造になっているため、錆びやすく切れ味もよいし、研ぎやすいはずだ。

今回のボドゲ会では、去年に買ったまま放置していたイカサマゴキブリが開封されてプレイされていたようだ。私はプレイできなかったのが残念だ。

さて、毎月第一土曜日に開いている江添ボドゲ会も、だいぶ定着してきた。ただし、部屋が狭すぎるように思う。これを解決するためにも、また、通勤の手間を省くためにも、そろそろ引越しをしたくある。引越し先はリビングの面積を重視したい。しかし、そうすると自分でシェアハウスを建ち上げるのがよく思えてきた。

条件としては、職場の徒歩圏内に家が欲しい。リビングが広くてボドゲが開催できること。4部屋以上あることだ。いくつかふさわしい物件を見つけ、実際に不動産屋に聞きに行っているのだが、どうもなかなか決まらない。すでに先約があったりする。中でも惜しかった物件は、まだ人が住んでいて来月まで内見すら出来ないのに、すでに申し込みが入っているそうだ。流石に現物を見ずに申し込みなどできるわけがないので、惜しいながらも以下の物件は見送った。

【SUUMO】東京都江東区富岡1/門前仲町駅の賃貸・部屋探し情報(100027149628) | 賃貸マンション・賃貸アパート

法人契約が必要な物件は広告でその旨を書くべきだと思う。検討するだけ時間の無駄だ。

もうひとつ、東京の賃貸事情で特殊なことには、ある程度の規模の賃貸となると、所有者が法人相手にしか貸さないということだ。リスク回避のためでもあろうが、そのせいで借り手がいないのであれば大変な機会損失ではないのだろうか。とある場所に、同僚が5人で住めば実質一人あたりの月負担が2万円という素晴らしい物件があったのだが、法人契約を要求されたため諦めた。弊社社員は、職場近くに済むことが多いのだが、銀座近くは、ワンルームでさえ月9万円が最低価格だ。それを考えれば実にいい物件なのだが、所有者が貸さないというのであればどうしようもない。

そういえば、先週末に京都に行った時、町中を歩いているて不動産屋の前の広告をチラと眺めた時、筆者は思わず愕然としてしまった。西大路通に4LDKが月6万で出ているではないか。しかも礼金なしだという。何らかの理由があるのであろうが、それにしてもこの価格はありえない。いや、京都が安いのではない。東京の賃貸価格が高すぎるのだろう。

今はこの物権をねらっている。

【SUUMO】東京都江東区佐賀1/門前仲町駅の賃貸・部屋探し情報(100027332062) | 賃貸マンション・賃貸アパート

2015-06-05

C++標準化委員会の文書 2015-04-pre-Lenexaのレビュー: N4410-N4419

N4410: Responses to PDTS comments on Transactional Memory

Transactional Memory TSに対するNBコメントに対する返答。

日本からは反対意見をいくつか送った。

JP1では、トランザクショナルセーフという概念がmath.hにも適用されるのは既存のコードのパフォーマンスの劣化を招く恐れがあるという反対意見を送った。例えば、浮動小数点数の精度を実行時に非トランザクショナルセーフに変更する実装が多いが、これをトランザクショナルセーフにするには、極めて高いコストを支払わなければならないという懸念だ。

回答はrejectされた。math.hは意図的にトランザクショナルセーフから外されているとのことだ。

前回のC++WG JPの会議では、それならば問題はないが、ドラフトにはそのような文面が見当たらないので要確認という結論になった。

JP2では、関数のブロックスコープのstaticストレージ上の変数は非トランザクショナルセーフにすべきだという反対意見を送った。アトミック実行が非アトミック実行と同期しなければならなくなる懸念がある。

回答は、rejectされた。関数のブロックスコープのstaticストレージ上の変数はトランザクショナルだろうが非トランザクショナルだろうが、アトミックであるべきだという合意があるからだという。現行の規程が、非トランザクショナルなコードパスに余計なオーバーヘッドをもたらす懸念はないという。

これを受けての日本での議論は詳細に覚えていないが、まあ、コンパイラー屋も出席する会議でそういう合意が得られたのであればそうなのだろうという雰囲気だったような気がする。

N4411: Task Block (formerly Task Region) R4

fork-joinライブラリとして、Task Blockライブラリの提案。前回までの提案では、Task Regionと呼ばれていたが、OpenMPの文脈で別の意味に使われていて混同される可能性があるということ、task regionは名詞であるので、関数名としては、動詞が好ましいことから、task blockに解明された。また、task_region_finalに何らfinal的な意味合いはないのでdefine_task_block_restore_threadに改名した。task_blockクラスを作る関数をtask_regionをdefineプレフィクスをつけてdefine_task_blockにしたので、task_region_handleもhandleサフィックスをとってtask_blockに改名した。

利用例

template<typename Func>
int traverse(node *n, Func&& compute)
{
    int left = 0, right = 0;

    define_task_block([&](task_block& tb) {
        if (n->left)
            tb.run([&] { left = traverse(n->left, compute); });
        if (n->right)
            tb.run([&] { right = traverse(n->right, compute); });
    });

    return compute(n) + left + right;
}

N4412: Shortcomings of iostreams

i2015-02-24のCologne LWG会議でostreamの問題点の話し合いをまとめた文書らしい。

XMLやJSONのようなデータのテキスト表現を行うプロトコルがあり、この場合の機械的に精製されたテキスト表現はロケールに依存すべきではない。

整数や浮動小数点数と文字列との相互変換の方法が簡単にできない。

浮動小数点数に関しては、値をテキスト表現に変換して戻す信頼できる方法が存在しない。

std::streambufはBase64エンコードのようなバイトストリーム処理に適してない。

std::filebufのようなものはコード変換を行うべきではない。コード変換はstd::streambufのフィルターとして行うべきだ。

入出力操作におけるOSのエラー通知はユーザー側に渡されるべきで、ライブラリで握りつぶすべきではない。

フォーマット方式はフラグで設定するが、これはstreamオブジェクトに状態として維持されてしまう。

iostreamは文字型とchar_traitsによるテンプレート化がなされているが、char_traitsは現実的に使われていない。

a<< b << c << dのようなチェインは、型安全に任意個の値を出力できるという点では成功したインターフェースだ。ただし、ソフトウェアの規模が大きくなると、オーバーロード解決が煩雑になる。解決不可能だ。

C++11ならば、Variadic Templatesのよるprintfのようなインターフェースが可能になる。

Matt WilsonのFastFormatライブラリや、Boostのlexical_castを参考にしたAPIを考察する価値がある。

ユーザー定義型に対する入出力を拡張できる機能は必須だ。

現在、moneyとtimeのfacetが使われていない。

ロケールが深く組み込まれている。ロケールはグローバルオブジェクトなので、出力する関数呼び出しごとに二回の同期が必要になる。

ロケールは不完全だ。ICUなどの現実的なライブラリを参考に設計すべきだ。

テキストの内部表現は統一したほうが都合がいい。UTF-32は固定長エンコード(寝ぼけてるのか?)だがメモリーフットプリントがUTF-8より多い。

個人的には、iostreamは完全に設計が破綻しているので、これ以上改良を加えるより、捨てたほうがいいと思う。

[PDF注意] N4414: Executors and Schedulers Revision 5

executorライブラリの提案。

ある処理を並列実行するさいに、どのように並列実行するかという方法を、executorという概念から使うことができる。

executorは、void spawn( Func && )という共通のメンバー関数を持つ。

標準では、thread_per_task_executor、thread_pool_executor、loop_executor(タスクを積んでいって一気に呼び出し元のスレッドで処理する)、serial_executor

リファレンス実装が公開されている。

https://github.com/ccmysen/executors_r5/tree/master/include

[PDF注意] N4415: Simple Contracts for C++

契約プログラミングをコア言語でサポートするための提案。属性ベースの機能のようだ。

契約とは、関数の事前条件と事後条件を保証するためのもので、高級なassertとみなすこともできる。

ただし、その目的はエラー報告でもテストフレームワークでもない。期待する動作との齟齬を検出するための基礎的な機構だ。

すでにライブラリによるサポートの提案は出ていたが、コア言語でのサポートの声も大きいので、これはコア言語でサポートをする提案となっている。

契約は関数宣言に属性で記述する。契約に記述された式を評価した結果がfalseとなれば、契約は満たされない。

契約は関数宣言に記述するが、型の一部ではない。ただし、関数は名前で直接呼び出されても、関数へのポインター経由で呼びだされても、契約によるチェックは行われる。

この論文で提案されている文法は、属性を使うものだ。

[[ expects : condition ]] で呼び出す前の事前条件を指定する。

[[ ensures : condition ]] で呼び出した後の事後条件を指定する。

たとえば、Vectorクラスの添字演算子の事前条件は、以下のように書ける

T & operator [] ( size_t i ) [[ expects : i < size() ]] ;

同様に、ArrayViewクラスのコンストラクターの事後条件は、以下のように書ける。

ArrayView( const vector<T> & v ) [[ ensures : data() == v.data() ]] ;

契約はどのように動くのか。

契約の条件式は型チェックされる。

関数の本体が実行される前に、事前条件が評価される。結果がtrueであれば、関数の本体は通常通り実行される。結果がfalseであれば、実行の継続は保証されない。プログラムはabortするか、例外を投げるか、あるいは挙動が未定義ながらそのまま実行を続けるかなど、何らかの実装依存の挙動をする。つまり、規格準拠の実装は契約をすべてチェックしてもいいし、一部のみチェックしてもいいし、あるいは無視してもよいということだ。

同様に、事後条件は関数の戻り値を返した後、ローカル変数を破棄した後、呼び出し元に処理が反る前に評価される。結果がtrueであれば、通常通り処理が継続する。結果がfalseであれば、プログラムは事前条件と同じように、異常終了など、何らかの実装依存の挙動をする。事後条件は例外によって関数を抜けた場合は評価されない。

ここで提案している契約は、あたかもassert( condition )を関数の前後に配置して(ローカル変数などにアクセスできないという制約はあるが)実行したように振る舞う。この設計には現実的な理由がある。

契約チェックの有効無効、一部のみ有効を切り替えることができる。マクロなどを使った切り替え方法を提供することは考えていない。正しいプログラムが正しいデータに対して実行された時は、契約を無視するのは、プログラムの観測可能な挙動に影響を与えないはずだ。つまり、デッドコードの除去的な最適化手法とみなすこともできる。実装は契約チェックの有効無効を切り替える方法を提供することが推奨される。

契約チェックはどの粒度で行われるべきだろうか。関数の宣言単位だろうか。クラス定義定義だろうか、名前空間、翻訳単位、あるいはプログラム全体か? 関数ごととか、プログラム全体の粒度というのは、ほとんどのプログラムにとって現実的な粒度ではない。クラスごととか名前空間ごとなどというのも茨の道だ。この提案では、翻訳単位ごとの契約の切り替えを提案している。

契約が満たされなかった時に、std::abortを呼び出すのは、プログラムによっては適切ではない場合もある。例外を投げたほうがいい場合もあるだろう。ただし、組込みシステムなどの資源が希少な環境でも使えるようにすることを考えると、例外を必須にはできない。関数へのポインターを設定することによるコールバック関数も、デッドコードの除去という点で難しい。多くの超重要なシステムは、不必要なコードを絶対に入れないという厳しいポリシーを持っている。

2014年のUrbana, IL会議でも好まれたように、この提案では、契約違反の挙動を実装依存とし、契約チェックを、all, none, pre-condition, post-conditionだけに限定することを翻訳単位ごとに切り替えるようなことを認める。

この提案に含まれないもの。

この提案は単純化のために、契約プログラミングとして有益な機能の多くを省いた。たとえば、invariantsとか、abstract statesとか、関数の本体に入った際の最初の実引数の値を参照できる機能とか、事後条件で関数の戻り値を参照できる機能だとか、例外時の契約チェックだとかだ。これらの機能は、その価値を判断して無益だと結論したから取り入れなかったのではなく、C++に契約を入れるにあたって単純なものを先に入れ、進化的に改良していく手法をとりたいからだ。

この提案は、既存のABIに変更を加える必要はない。単に型チェックだけを行って後は無視する実装も規格準拠の実装だ。また、実装は事前条件、事後条件に相当するassertを機械的に挿入するだけでも規格準拠となる。このような実装戦略はABIの変更を必要としない。実装は、契約による情報を、挙動を変えない限り、コード生成のヒントとして使うことができる。

関数が複数箇所で宣言される場合、契約は全てに書くべきか。省略すべきか。理想では、契約は一箇所のみに書くべきであるが、単純化のために、以下のルールを提案する。ある翻訳単位で、宣言が契約を持つ場合、後続の宣言もすべて、ODR的に同一の式を持つ契約がなければならない。また、関数宣言が契約を持つ場合、その定義も契約を持たねばならない。実装には翻訳単位を超えて契約が正しいことを確認する義務はない。宣言では契約を書かず、定義だけ契約を書くことも許容される。これはインターフェースから契約を隠すことになるので、その意義は疑問だが。

契約に書ける式とは何か

契約の条件式は、副作用フリーであるべきだ。すなわち、その評価の有無はプログラムの観測可能な挙動に差を生じさせるべきではない。その意味では、constexpr関数に近い。ただし、constexpr関数に限定するのは現実的ではない。そのため、提案では、単に契約の式は副作用フリーであるべきだと記述するに留める。

virtual関数について

virtual関数のオーバーライドは、基本クラスのオーバーライドされるvirtual関数の契約も受け継ぐ。オーバーライダーが契約を記述する場合は、元の関数と同じ契約でなければならない。契約を弱めたり強めたりすることはできない。

struct A
{
    bool f() const ;
    bool g() const ;
    bool h() const ;

    virtual void v() [[ expects : f() && g() ] ;
} ;

struct B: A
{
    void v() ; // OK、継承する
} ;

struct C : A
{
    void v() [[ expects : f()  ]] ; // エラー、弱化
} ;

struct D : A
{
    void v() [[ expects : f() && g() && h() ]] // エラー、強化
} ;

オーバーライド先で事前条件を弱めたり、事後条件を強めたりするのは、技術的に妥当だが、この提案は機能の簡潔さを目的としているので、そのような機能を今回は提案しない。

クラスのメンバー関数の契約が参照できるメンバーとはなにか。

契約はインターフェースの一部であるので、契約でprivateなメンバーを参照してしまうと、隠匿流出になってしまう。この提案では、契約の条件式は、メンバー関数のアクセス指定と同じだけのアクセスができると規定している。

  • publicメンバー関数の契約は、publicなメンバーのみを参照できる
  • protectedメンバー関数の契約は、publicとprotectedなメンバーを参照できる
  • privateメンバー関数の契約は、すべてのメンバーを参照できる。

friend宣言で関数を定義している場合は、publicなメンバーのみ参照できる。

属性の文法拡張

この提案は、現在のC++11で導入された属性にはない文法として、コロンを使っている。[[ expects : condition ]], [[ ensures : condition ]]。既存の属性の文法で書くと、[[ expects(condition ) ]], [[ ensures(condition) ]]となる。論文では、コロン記法は、C++11のLisp風の属性記法より、読みやすいので、契約以外にも有益であるとして、属性の拡張も提案している。

関数ポインターは、契約の有無は問わない。

double f( double x ) [[ expects : x >= 0.0 ]] ;
double (*pf)( double ) = &f ; // OK

ポインターを契約付きで宣言することもできる。契約がない関数へのポインターを契約付きの関数へのポインター宣言に代入しようとするとエラーになる。


double f( double x ) [[ expects : x >= 0.0 ]] ;
double (*pf)( double ) [[ expects : x >= 0.0 ]] = &f ; // OK

double g( double x ) ;
double (*pg)( double ) [[ expects: x != 0.0 ]] = &g ; // エラー

コア言語に組み込むことで、解析ツールによるサポートもしやすくなった。

Bloombergの提案N4378との比較

Bloombergの提案は、「契約assertの言語サポート」という銘打っているものの、言語サポートについてはよく分からず、その実体は、いいところが単なるasertフレームワークでしかない。その設計はプログラマー外とする箇所に手動で仕込むことを想定している。インターフェースレベルで契約を表現する方法はないし、コンパイラーやツールが効率的に解析できる機構にもなっていない。この提案の想定は、契約とは非公式に英語で書かれるものであって、インターフェースレベルでコード上に書くものではないというものだろう。明らかに、これは解析ツールの役に立たず、契約内容を呼び出し元から見ることもできない。さらに、assert管理はグローバルであるため、assertの利用を完全に決定できる中央権威が存在しなければならない。これは、複数の部署、団体が書いたコードを組み合わせる、たいていの環境のプログラムには適用が難しい。契約assertのコンポーネント単位の管理をないがしろにしてはならない。

N4293との違い

文法をキーワードから属性にした。契約は、正しいプログラムであれば、取り除いても何ら観測可能な挙動に影響を与えないものであるから、属性を使うのは理にかなっている。

N4293で提案されている機能のいくつかを、本提案は単純化のためにサポートしていない。これは将来の拡張に期待したい。

[PDF注意] N4416: Don't Move: Vector Can Have Your Non-Moveable Types Covered

タイトルが面白い。

vectorにコピーもムーブもできない要素型に対応させるためにメンバー関数テンプレートを追加する提案。

C++03のvectorは、コピーできない要素型を扱えなかった。C++11になって、コピーできなくてもムーブできれば扱えるようになった。ただし、ムーブすらできない型は依然として扱うことができない。

vectorがコピーかムーブを要求する理由は、内部ストレージのサイズが足りない場合に、より大きなストレージを確保してオブジェクトの移し替えを行うからだ。

ところで、最近、mutexやatomicをデータメンバーに持つクラスが増えてきている。これらのクラスは、暗黙にコピーもムーブもできない。しかし、このクラスのオブジェクトの集合をvectorに入れて管理したい。

ではどうするのか。提案では、厳密にストレージのサイズを指定するメンバー関数テンプレートと、ストレージのサイズの伸長を行わないemplaceを追加することで対応している。このメンバー関数テンプレートのみを使って要素の追加を行えば、ムーブ不可能な型でも対応できる。

void reserve_initially(size_type n)

コンテナーがempty()の時のみ、厳密にn個の要素分のストレージを確保する。

template <class... Args> void
emplace_back_capped(Args&&... args)

size() < capacityのときのみemplaceする。

emplace_back_cappedが失敗した場合はどうするのか。例外を投げるのか。絶対失敗しないことを事前条件とするのか。提案では、既存のemplaceもストレージを確保できない時は例外を投げるし、既存の挙動と一致するので例外を投げるとしている。

その他には、resizeがある。resize_capped(n, args ...)は、empty()のときに、厳密にn個の要素分のストレージを確保してargs...で構築した要素でemplaceする。resize_downはn <= size()のときにn個にリサイズする。

提案では、一貫性を保つために、dequeやlistやvector、その他のコンテナーアダプターにも同等のメンバーテンプレートを追加することも考察している。

[PDF注意] N4417: Source-Code Information Capture

__LINE__, __FILE__, __func__に変わるまともなソースコード情報を取得できるクラスライブラリの追加提案。静的リフレクション機能の一つだ。

前回の提案であるN4129からの変更点は、offset_from_start_of_fileの削除と、コンストラクターにコンパイラーマジックがなくなったこと。かわりにcurrentが追加された。あとp

int main()
{
    std::source_location info ; // この場所のソースコード情報を保持

    std::cout
        << "line: " << info.line_number() // 行番号
        << "\ncolumn: " << info.column() // 行頭からの文字数
        << "\nfile name: " << info.file_name() // ファイル名
        << "\nfunction_name" << info.function_name() // 関数の本体の中の場合関数名、それ以外の場合は空文字列
        << std::endl ;
}

関数の引数に渡すために、特別なconstexpr staticメンバー関数currentが用意されている

// ログ記録用の関数
void logger( std::source_location info ) ;

int main()
{
    logger( std::source_location::current() ) ;
}

currentは呼び出された箇所に相当するsource_locationの値を返す。

[PDF注意] N4418: Parameter Stringization

実引数として与えられた呼び出し元の式を文字列化して取得する機能を追加する提案。これも静的リフレクション機能に分類される。

CプリプロセッサーマクロにできてC++にできないことのひとつに、引数式を文字列化するということがある。


void custom_assert( bool cond )
{
    if ( ! cond )
    {
        std::cout << "assertion failure!: " << "引数に渡した式の文字列" << std::endl ;
    }
}

void f( int * ptr, std::size_t size )
{
    custom_assert( ptr != nullptr ) ;

    // ...
}

このようなコードを実現するには、Cプリプロセッサーマクロの#演算子を使わなければならない。


void custom_assert_impl( bool cond, const char * expr_str )
{
    if ( ! cond )
    {
        std::cout << "assertion failure!: " << expr_str << std::endl ;
    }
}

#define custom_assert ( expr ) custom_assert_impl( (expr), #expr )

void f( int * ptr, std::size_t size )
{
    custom_assert(( ptr != nullptr )) ;

    // ...
}

この提案は、C++にはこのプリプロセッサーの代替機能が必要であるとしている。具体的な文法についてはまだ深く考えられていない。

[PDF注意] N4419: Potential extensions to Source-Code Information Capture

source_location提案に対する拡張提案。

最新の提案では削除されたoffset_from_start_of_fileの追加

行番号に対応するsource_locationを取得する機能の追加。

取得する情報を選ぶことができる機能

大量の長い関数名が存在するソースコードで、関数名情報を取得する場合は、バイナリに関数名を埋め込まなければならず、バイナリが肥大化する。そのために、必要な情報の一部だけを取得できるように、取得する方法を指定できる機能。

ユーザー定義の情報をsource_locationに仕込める機能。

function_nameで得られる名前はデマングルされていないものであることが予測されるので、デマングルした人間に読みやすい名前に変換する機能

ドワンゴ広告

最近、ドワンゴ社内で、何らかの理由により、業務外で交流のない人間と食事に行く需要がにわかに発生しているため、マッチングサービスの実装が望まれている。また、レコメンド機能があると便利かもしれない。「この社員と食事に言った人はこんな社員とも食事に行っています」

また最近、ドワンゴ社内で始まった謎の制度のせいで、アマゾンで特定の技術書が売り切れるという現象が発生しているようだ。

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

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

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