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