2014-05-pre-Rapperswil mailingのレビュー: N3990-N3999
C++WG論文がたまっているので消化していきたい。
[出だしからPDF] N3990: Adding Standard Circular Shift operators for computer integers
サーキュラーシフト演算子(Circular shift operators)、つまりローテート演算子の提案。
サーキュラーシフト演算子とは、シフト演算子に似ているが、あふれでたビット列が、反対側に現れる。つまり、11110000という8bitの整数を左に2、サーキュラーシフトすると、11000011となる。
ローテート操作は、暗号計算などの分野で多用されているため、高速である必要がある。多くのアーキテクチャでは、ローテート操作をするプロセッサーネイティブの命令が存在する。しかし、C言語では、ローテート操作のための標準的な方法が存在しなかった。そのため、標準C++の枠内で移植性のある実装をするには、既存のシフト演算子を使わなければならない。
GCC 4.7以降では、そのようなシフト演算子を組み合わせたローテート操作を認識し、ローテート命令のあるターゲット向けならば最適化できる。しかし、単にコードを読み書きする都合からも、標準の方法が存在すべきである。
提案されている演算子は、<<<. >>>, <<<=, >>>=の4つである。意味は明らかだろう。この演算子は、もちろんオーバーロード可能だ。
サーキュラーシフト演算子の左辺は、符号なし整数でなければならない。もし、符号付き整数が指定された場合の挙動は未定義である。
void f( int x )
{
// 挙動は未定義
x <<< 1 ;
}
サーキュラーシフト演算子の右辺は、正の整数で左辺の整数型のビット数未満でなければならない。右辺が負数であったり、左辺の整数型のビット数以上であった場合の挙動は、未定義である。
// 1バイトは8bitであるとする
void f( unsigned int x )
{
// 挙動は未定義
x <<< -1 ;
// 挙動は未定義
x <<< sizeof(x) * 8 ;
x <<< sizeof(x) * 8 + 1 ;
}
挙動は未定義であって、ill-formedであるとは定められていない。もちろん、未定義であるからして、ill-formedとなっても規格準拠の実装である。ゼロ除算と同じような扱いだ。
[またPDF] N3991: Task Region R2
fork-joinという考え方の並列実行のための高級ライブラリ、Task Regionの提案。前回の論文、N3832からの変更点としては、task_regionから発生した子タスクと明示的に通信するためのtask_region_handle。
N3992: Agenda and Meeting Notice for WG21 Telecon Meeting
6月6日に開催された電話会議の予定表
[まだPDFだ] N3993: On Parallel Invocations of Functions in Parallelism TS
現在TSに提案されている、<algorithm>に実行ポリシーによるタグディスパッチを追加して、並列実行やベクトル実行が出来るようにしようという提案の文面案で、ソートはswapを並列に呼び出すが、要素がオーバーラップしない時だけに限るという保証を与えるために、Hans Boehmが文面案を改正すべきだという意見を出したので、それに伴い、文面案を変更する提案論文。
N3994: Range-Based For-Loops: The Next Generation (Revision 1)
range-based for loopで、for ( elem : range ) を、for ( auto && elem : range )にするための軽いシンタックスシュガーの提案。
N3995: A proposal to add shared_mutex (untimed) (Revision 2)
C++11でshared_mutexと呼ばれていたものは、TimeLockable要件(try_lock_for/try_lock_until)を満たすので、実はshared_time_mutexと呼ぶべきであったので、そのように改名する提案が可決された。そこで、TimeLocakble要件を満たさない、本当のshared_mutexを追加する提案。
[長大なPDF] N3996: Static reflection
130ページもある長大なPDFの論文。
静的リフレクションに関する論文。
例えば、クラスの内部状態をバイナリとかXMLとかJSONなどといった何らかのフォーマットに書き出したり、そのフォーマットから読み込んでクラスの内部状態を再現したりしたいとする。これは一般に、Serializationと呼ばれている。serializationを実装するには、クラスの意味のあるデータメンバーをそれぞれ読み書きする必要がある。これを手動であらゆるクラスに対して手で書くのは面倒である。極めて単調で、機会的に生成できるコードである。何か、クラスのデータメンバーをコンパイル時に列挙して、それを元にコンパイル時にコードを生成するような機能があればいいのだが。
その機能を提供するのが、リフレクション(Reflection)だ。リフレクションによるリフレクティブプログラミング、これはメタプログラミングの一種である。そのリフレクションをコンパイル時に行うので、静的リフレクションとなる。
論文は、静的リフレクションで取得可能なコード情報や、Technical Specification文面案など、やたらと大量の文章を含むので、ここまで膨れ上がった。
[PDFから身を守りたい] N3997: Centralized Defensive-Programming Support for Narrow Contracts (Revision 5)
防衛的プログラミングと称して、高機能assertマクロをライブラリとして追加する提案。
筆者はCプリプロセッサーを使う提案に反対の立場である。
N3998: C++ Latches and Barriers
ラッチとバリアーというライブラリの提案。
ラッチというのは、ひとつ以上のスレッドをブロックしておくためのライブラリである。ラッチは初期化時にカウントを指定する。latch::arrive()を呼び出すことで、カウンターがデクリメントされる。カウンターがゼロに達すると、latch::wait()を呼び出すことでブロックされていたスレッドが実行を再開する。
// ラッチオブジェクト
// カウンターは3
std::latch l( 3 ) ;
// (複数の)スレッド
void waiting_thread()
{
// 処理がすべて終わるまで待機
l.wait() ;
}
// 処理、三回呼ばれたらラッチによるブロックが解除される。
void operation()
{
l.arrive() ;
}
ラッチは、一度きりしか使えず、再利用できない。
バリアーは、再利用できるラッチである。
さらに、notifying_barrierというクラスもあり、これは、終了条件に達した時点で、設定した関数が呼ばれるものである。
それにしても、どうも名前が聞きなれなくてややこしいと思うのは筆者だけだろうか。とくに、スレッド間の同期でいえば、ずぼらな人のためのアトミック操作であるメモリバリアーとややこしいと思うのだが。
[またPDF] N3999: Standard Wording for Transactional Memory Support for C++
トランザクショナルメモリーの文面案。前回からの変更は小粒。
ドワンゴ広告
この記事はドワンゴ勤務中に書かれた。
今日、社内で謎のダンスが流行っていた。
ドワンゴは本物のC++プログラマーを募集しています。
CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0