2013-10-20

2013-10 post-Chicago mailingの簡易レビュー

2013-10 post-Chicago mailingが公開された。

最新のドラフト規格は、N3797、Editor's Reportは、N3798になる。

今回は、前回のCDに入れ忘れていた[[deprecated]]を入れた。また、数値区切りもオランダ、アメリカ、スペインの激しいNBコメントの圧力で入った。他にコア言語として大きな変更は、Sized Deallocationだろう。ライブラリとしては、run-time sized arrayの同等機能をライブラリで実現するdynarrayが入った。CD後だが、機能追加が激しい印象がある。

[悪鬼PDF] N3770: C++ FCD Comment Status

オランダ、アメリカ合衆国、スペインが、数値区切りは必要だから絶対入れろとNBコメントを出したので、さすがに圧力に負けて、数値区切りが入った。早急過ぎる感がある。

UTF-8文字列リテラルの型がconst char []だが、charでは表現できると保証されていない0x80とかの値がでてくる。どうするんだよ。charが0x80を表現できることを保証するか、型をunsigned charに変えろという大ブリテン及び北アイルランド連合王国の主張には、将来的に対応するという返答がなされた。まだ対応するcore issue #1759は空っぽだが、いずれ議論されるだろう。

スペインの主張したsized deallocationも追加された。

[[deprecated]]が、入ると合意されたのにドラフトの文面に入れ忘れているというコメントも、修正された。

アメリカ合衆国の、run time sized arrayについて、C99では配列の添字として0を使うのは合法なのだが、C++14のドラフトでは実行時例外を投げるとされている。これはCとC++の互換性を損なう。C99に合わせるべきだというコメントについては、受け入れられた。

全体的にみると、NBコメントは概ね受け入れられている。スイスのC++14はマイナーアップデートだからバグ修正のみにしろ、機能追加をするなとかは未回答で、スペインの、lambda式のクロージャーオブジェクトをリテラル型にしろというのは、さすがにそんなコンセンサスが得られないとして拒否されたが、やはりNBコメントは強い。

今回、C++WGの日本支部からは、NBコメントを送っていない。というより、この数年、日本支部の活動はほぼ停止している。これは、どうも国内にC++のスポンサーをする企業や団体がいなくなったからだと思われる。最近入ってきた若いメンバーが、とりあえず活動を再開しようと、C++WGの枠外で、勉強会を開くそうだ。これは、企業のスポンサーがなくてもできる活動だが、このままでは日本におけるC++は草の根レベルの活動に落ちてしまう。日本支部の存在する理由が薄れてしまう。

その結果として、C++の日本語への配慮がなくなったり、日本からのC++規格への影響がなくなったり、C++の日本語の資料がなくなったりするだろうが、まあ、私の知ったことではない。スポンサーがいなければ、消えゆくだけだ。C++98の時代には、国内にC++のスポンサーが結構いて、そのおかげで、C++98のISO標準規格の日本語訳であるJIS規格もでた。C++11では、そのようなスポンサーがいないため、JIS規格はない。

[外道PDF] N3771: Canadian C++14 Comments

カナダからのNBコメント。なぜか論文が独立している。コメントが多かったからだろうか。提出が遅れたからだろうか。

[無知蒙昧PDF] N3772: Changing the type of address-of-member expression

メンバーへのポインターの挙動を変える提案。C++の型システムが関わってくるので、短いもののものすごく難解。

C++では、ベースクラスへのメンバーへのポインターは、ベースクラスへのメンバーへのポインター型になる。

struct A { int member ; } ;
struct B : A { } ;

auto ptr = &B::member ; // 型はint A::*

&B::memberなのに、型はint A::*になってしまうのだ。

何が問題なのかというと、テンプレートに渡した時だ。

struct A { int member ; } ;
struct B : A { } ;

template < typename T, int T:: * PTR >
struct C { } ;

C< B, &B::member > c ; // エラー

なぜこれがエラーになるのかというと、テンプレート実引数に渡す文脈では、適用される型変換が極めて少なくなるからだ。&B::memberの型は、すでに述べたように、int A:: *となる。ベースクラスへのメンバーへのポインターを派生クラスへのメンバーへのポインター型に変換するというのは、テンプレート実引数に渡す文脈では適用されない。

そのため、明示的なキャストが必要だ(と論文では書いているが、なぜかGCCでもClangでも通らない)

C< B, static_cast< int B::* >( &B::member ) > c ;

なんだこのマヌケなコードは。これはおかしいだろう。ということで、これが通るようにしたい。

もうひとつの例としては、privateで派生して、using宣言でメンバーをpublicに出す例

struct A { int member ; } ;
struct B : private A
{
public :
    using A::member ;
} ;

int main()
{
    int B:: * ptr = &B::member ; // エラー
}

これもおかしい。

他には、well-formedになってほしくないけどwell-formedになってしまう例とか、この問題を解決するための変更によりバイナリ互換が壊れる例を挙げている。

[廃止されるべきPDF] N3774: async and ~future (Revision 4)

std::futureのデストラクターはブロックするべきという主張がある。しかし、互換性の問題もある。この論文は、ブロックしないfutureとブロックするfutureを、それぞれ別の型で表現することを提案している。

そもそも、std::asyncとstd::futureは、その貧弱な機能から、すでに廃止が主張されている。あるいはそのまま手を付けずに残して、もっとまともな代替ライブラリの設計に力を入れるべきだという意見もある。

[C++論文にPDFは必要ない] N3774: C++ Needs Language Support For Vectorization

C++は言語としてベクトル化をサポートするべきであると主張する論文。ベクトル化は並列化とは異なるものであり、独立したサポートが必要である。C++が言語として直接にベクトル化をサポートしていなければ、ベクトル化の利用が難しいと主張している。

CERNで得られた知見をもとに書いている。

現在のベクトル化のアプローチには三種類ある。コンパイラーによる自動ベクトル化、ベクトル用のIntrinsic、アノテーションによるコンパイラーに対するベクトル化のヒントの指定がある。

コンパイラーによる自動ベクトル化は、めったにうまくいかない。なぜならば、ベクトル化はC++に規定された挙動とは全く異なる、再現性のない処理だからだ。そのため、コンパイラーは確実に挙動が変わらない部分しか自動ベクトル化できない。

ベクトル用のIntrinsicは便利だが、そのために特殊なコードをかかなければならない。

アノテーションによるベクトル化のヒントは、かなり自然に書くことができる。

[PDFもdepreacated扱いすべき] N3775: Deprecating rand() and Friends

rand()を含む一部のライブラリをdeprecated扱いにする提案。rand, srand, RAND_MAX, randome_shuffleがdeprecated扱いになり、文面はAnnex Dに移動される。

かわりに、C++11で新しく追加された乱数ライブラリを使うべきである。C++11では、random_shuffleの代わりとなる、もっとマシなインターフェースのshuffleが追加されている。

これはすばらしい提案だ。ぜひとも採用されてほしい。

[PDFを論文に使わない義務も文面化するべき] N3776: Wording for ~future

futureとshared_futureのデストラクターはasyncが絡まなければ、ブロックしないという保証を明確にする文面の提案。

[PDFをdeprecateする文面はいずこ] N3777: Wording for deprecating async

SG1の投票で、asyncはdeprecatedすべきという結果がでたので、そのための文面の変更案。

N3778: C++ Sized Deallocation

解放関数のオーバーロードに、解放すべきストレージのサイズを得られる引数を追加する提案。これにより、いくつかのメモリ確保のテクニックが使いやすくなる。

[PDF嫌い] N3779: User-defined Literals for std::complex

std::complex用のユーザー定義リテラルの提案。

とても興味深いことに、ifという名前のユーザー定義リテラルを使っている。ユーザー定義リテラルの名前はentityではないので(operator "" _name全体がentityとなる)、実装上、キーワードも使うことができるとはいえ、まさか本当にそんな提案をするとは。

[PDFを論文に使用するのは最悪の選択肢である] N3780: Why Deprecating async() is the Worst of all Options

久しぶりにNicolai Josuttisさん。有名なC++の参考書の第二版を書くときに、std::asyncから返されたfutureが、get()もwait()もしない場合、ブロックするのかどうかということについて、疑問に思ったので、標準化委員会で相談してみたところ、何と今行われている一連のasyncとfutureのブロック議論のきっかけとなったそうだ。果てにはasyncのdeprecated案まで投票で合意される始末。

Josuttisとしては、asyncは廃止されるべきではないとしている。なぜならば、asyncはお手軽なライブラリであり、他に代替案がない。現在設計中のライブラリがTRで出るとしても、まだ先の話で、もちろん実装もなく、動かない。それに引き換え、asyncはすでに実装がある。代替案もない今、asyncを廃止すべきではないと主張している。

実際、2年前に追加された機能を即座にdeprecated扱いにするというのは、C++の歴史の中でも、かなり異質だ。

[気に食わんPDF] N3781: Single-Quotation-Mark as a Digit Separator

C++14に数値区切り機能を追加する。区切り文字は単一引用符

int x = 1'2345'6789 ;
double y = 1.2345'6789 ;
std::uint32_t bits = 0b11111111'00000000'11111111'00000000 ;

ソースコード上で、長い数値リテラルが読みやすくなる。

私はこの機能が気に入っていない。便利な機能であることは確かだが、もっと文法を議論してから入れるべきだったと思う。ただ、オランダ、アメリカ、スペインから、「必要だ、絶対入れろ」とNBコメントが来た以上、どうしようもない。

[PDF大嫌い] N3782: Index Based Ranges (Rev. 1)

Traversable(かつてRangeと呼ばれていた提案中のライブラリ)に添字ベースのアクセスを付け加える提案。

[PDFはまともなフォーマットに変換するべき] N3783: Network Byte Order Conversion

名前の通り、ホストのバイトオーダーをネットワークバイトオーダーに(もし必要であれば)変換するライブラリ。おなじみ、hton/ntohファミリーの関数群だ。C++らしく関数テンプレートになるが、従来の通常の関数も、POSIXとの互換性のために、提供される。

[PDFは改良しようがない] N3784: Improvements to std::future<T> and Related APIs

futureに非同期処理のためのメンバー関数を追加する提案。

N3785: Executors and schedulers, revision 3

処理単位を表現するexecutorと、executorを実行するschedulerライブラリの提案。バックエンドの実装としてはスレッドプールが一番わかり易い実装だが、スレッドプール以外にも実装の選択肢を考慮した設計となっている。たとえば、schedulerを呼んだスレッドでそのまま実行するというのも、実行処理がexecutorとなっているが、その場で実行したい場合などには便利だ。

N3786: Prohibiting "out of thin air" results in C++14

全く脈絡のない結果、あるいは文字通り、虚空から現れいでたる結果を禁止する提案。

全く脈絡のない結果というのは、複数のスレッドから同じオブジェクトにアクセスした結果、全く脈絡のない値が現れたりするもの。例えば、初期値0の非アトミックの通常のint型のオブジェクトに、排他的な同期処理を一切せずに、スレッドAでは1を代入し、スレッドBでは2を代入する。二つのスレッドを実行した後、オブジェクトの値を調べると、人生、宇宙、すべての答えである42がでてくるかもしれない。しかし、どちらも代入であるのだから、結果は未定義とは言え、代入したどちらかの値、あるいは初期値になるべきではないのか。それはそうであるのだが、実は、有益な最適化を妨げずに、問題となる「全く脈絡のない結果」を厳密に定義する方法を、我々はしらないということだ。つまり、どういう規格の文面を書けば、そのような好ましくない挙動だけを禁止できるのかわからない。

これは、Java規格でも10年以上、未解決のまま残っている問題である。

一方、全く脈絡のない値が現れるというのは、様々な面でよろしくない。第一常識に反する。セキュリティ上も問題だ。

何もしなくてもやたらと強い保証があるx86のようなアーキテクチャではなかなか実感しにくいが、ARMのようなアーキテクチャでは、それこそデータ競合に対して何の保証もないような無慈悲な挙動をしたりもする。

会議では、このことに関する一致した意見は出なかった。しかし、好ましくないことは確かであるので、C++14では、現在の文面を整理して、付記として、実装は全く脈絡のない結果が現れないよう努力するべきであるという文面を付け加えるべきだという方向に決まったらしい。

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

規格では、シグナルハンドラができることが、必要以上に制限されている。シグナルハンドラの制限は、もう少しゆるくてもいいのではないか。

シグナルハンドラでアトミックオブジェクトが使えるようにする文面の変更の副作用で、うっかりシグナルハンドラの制限が、volatile修飾でなければローカル変数すら使えないようなものになってしまった。このような誤りの制限を取り除くのは当然として、そもそも従来の制限も、必要以上に厳しすぎる。シグナルハンドラでは何ができるべきかということを、色々と議論した。その結果を反映した文面変更案。

N3788: C++ Standard Library Issues Resolved Directly In Chicago (2013)

シカゴ会議で解決されたいくつかの早急に対処が必要な問題集。

細かい問題ばかりなのでいちいちに挙げないが、最初の問題、2013は興味深い。

もし、標準規格で、ある関数にconstexprが付されていないとして、ある実装では、その関数をconstexpr関数の制約に落とし込めるとして、そのような関数にconstexprを付すことは、規格違反なのか。規格準拠な拡張なのか。

論文筆者は、現状では明確に規格違反であるとし、将来変更する可能性があるとは言え、現状がそうであるのだから、C++14では、規格に反してconstexprを付すのは規格違反であると明示する文面を付け加えるべきだとしている。これは解決された問題なので、C++14の文面はそのようになる。

すでに陶芸家が激怒している

N3789: Constexpr Library Additions: functional

functionalの比較オペレーターの関数オブジェクト(lessなど)をconstexprにする提案。

N3790: Draft Filesystem Technical Specification

[PDFカエレ] N3803: Programming Languages -- C++ Standard Library -- File System Technical Specification

filesystemライブラリのドラフト規格

N3791: Lightweight Graphical Interface

軽量グラフィックインターフェースということで、Study Groupを立ちあげて、描画の標準ライブラリを検討するそうだ。C++にそんなものが入るのか。

どうせ描画といっても、メインメモリ上のビットマップに描画するような純粋なものなんだろうと思いきや、なんとまともなグラフィックライブラリを目標としているらしい。すくなくとも、ウインドウを表示して描画してということができるべきだという。

グラフィックはとても難しい。MicrosoftやらAppleやらの提供するAPIや、あるいは、OpenGLやQtのような実装は、重量級のインターフェースである。このSG目的はそのような重量級の分野に踏み入ることではなく、軽量な、お手軽に使えるライブラリを目指すのだという。

そのため、このSGの名前は、Lightweight Drawing Study Groupとなった。

グラフィックインターフェースというのは、たとえ簡易的なものであっても、とてつもなく複雑で難しい。そのため、委員会による設計ではなく、既存の実装例を元にするのだという。できれば、GitHubのようなところにソースコードが存在して、作者もSGに参加できるようなライブラリが望ましい。

その土台となる実装例の要件として挙げられているものをみれば、軽量ドローイングとはいえ、C++の規格の手に余るような規模だ。

  • すでに広く使われていること
  • 近代的なC++設計であり、C++11/14の機能も使われていること
  • サードパーティによる拡張性があること。
  • 著作権などの知的財産権の所有者が、ISOの知的財産権要求に従えること
  • Bemanの提示した問題を解けること、「ウインドウ内にHello C++ Worldと表示し、ユーザーにその文字列をドラッグさせて、ウインドウ内で文字列を自由に動かせるプログラムを、既存のHello worldプログラムよりはいくらか複雑程度のプログラムで実現できること」
  • Herbの提示した問題を解けること、「ライブラリの基本を学んで、なにか面白いものを作るまで、4時間以内」

なんだか軽量とは程遠い要件のような気がするのだが。

論文は、このような要件を満たせる既存の実装例として、Cinderというライブラリを挙げている。

Cinder | The library for professional-quality creative coding in C++

CinderはBSDライセンスで、ウインドウ表示から描画までをサポートするお手軽なグラフィックライブラリである。残念ながら、GNU/Linuxはサポートしていない。

それにしても、C++の標準ライブラリとしてGUIを含むグラフィックライブラリとは、時代も変わったものだ。

N3792: Working Draft Technical Specification - URI

URIをパースするライブラリのドラフト規格

N3793: A proposal to add a utility class to represent optional objects (Revision 4)

optionalライブラリの提案。C++14に入る。

N3794: Proposal to Add Multi-Dimensional Support to std::array

std::arrayを多次元配列に対応させる拡張の提案。

N3795: A more common version of algorithm std::partition_copy

std::partition_copyとは、ひとつの入力を、二つの出力に、predicate次第で出力するものである。ところで、現実には、ある条件まで処理を進めて、途中で処理を打ち切りたい場合が多々ある。そのような場合に対応するため、partition_copyに、途中で処理を終了できるものを追加する提案。

N3796: std::rand replacement

std::randの代わりに、整数で範囲を指定して、その範囲から乱数を得る、std::randintを追加する提案。

std::randint( 1, 6 ) ; // 1から6までの範囲でランダムな値を返す

randintは、自動的に適切にseedされる。これは、randの設計は根本的にマズかったことに基づく、多くのコードが、std::srand( std::time(0) )のような不適切なseedを行ってしまっていた。

擬似乱数のseedの値を指定できることは、同じ乱数列を生成できることであり、デバッグや乱数列の再現など、利用例は多い。ただし、お手軽でグローバルな乱数としては、そのような機能性ではなく、不適切なseedを防ぐほうが有益であるとのこと。

このライブラリは、ユーザー側からみれば、std::randintひとつで完結している。単純な設計のため、間違いも少ない。もちろんスレッドセーフである。また、整数型しか対応していないが、関数テンプレートであり、任意の整数型に対応できる。つまり、型変換を起こさない。もっとも、整数リテラルを正しく使えばだが。

short x = std::randint( 1, 6 ) ; // 型変換が発生するので注意
short y = std::randint( 1s, 6s ) ; // // 型一致

N3800: A proposal to add a generalized callable negator (Revision 1)

従来のnot1やnot2よりもまともで近代的で使いやすいnegator、not_fnの追加。引数はいくつでもいい。

[PDFもC++論文から取り除きたい] N3801: Removing Undefined Behavior from the Preprocessor

既存のCプリプロセッサーの文面で、Undefined Behaviorとされている箇所は、すべてが、ill-formedにするとか、最低でも実装は条件付きでサポートすることもできるといったUnspecified Behaviorにできる。Cプリプロセッサーの現在の文面はUndefined Behaviorを多用し過ぎている。そこで、CプリプロセッサーからUndefined Behaviorを取り除く提案。

[PDF死すべし] N3802: apply() call a function with arguments from a tuple

tupleに格納された要素を実引数として関数を呼び出すライブラリ、applyの提案。

N3804: Any Library Proposal

Boostでおなじみの、どんな方でも格納できるライブラリ、anyの提案。

N3809: Proposal for Unbounded-Precision Integer Types

タイトル通り、上限なしの精度を持つ整数型の提案と思われる。なぜか論文がないので詳細は不明

[またぞろ配列] N3810: Alternatives for Array Extensions

C++14の実行時サイズ配列は好ましくない。何故ならば、暗黙にポインターが得られ、そのサイズが失われてしまうからだ。

C++14で、C99の可変長配列のように、sizeofでサイズを取得するのがサポートされなかった理由というのは、sizeofは要素数ではなく、バイト単位のサイズを返すため、間違いを犯しやすいと考えられたためだ。

論文では、実行時サイズ配列は安全ではないし、dynarrayでは不満足だとしている。そこで、最初からコンパイラーマジックが適用されることを想定した、もっと軽量なライブラリを提案している。仮にbs_arrayと名付けられていて、bsとは、論文によれば、Bike Shedだそうだが・・・論文筆者が他ならぬBjarne Stroustrup本人であることを考えると・・・いや、何も言うまい。

しかし、dynarrayですら、コンパイラーマジックが行われることを想定して設計されているわけで、ライブラリを乱立させてもいいことはないと思うのだが。この調子では、将来さらにyt_array(Yet Another)が出てくることは必然である。

N3814: Call for Reflection Proposals

コンパイル時リフレクションの提案。

今回検討するのは、コンパイル時のリフレクション機能。実行時リフレクションについては、まずコンパイル時リフレクションを検討してから、それに基づいて考える。

論文では、まだ検討段階で、コンパイル時リフレクションの設計を公募中であるとしている。コンパイル時リフレクションは、少なくとも、以下の利用例はカバーできるべきだとしている。

1. 共通関数の生成

利用例としては、たとえば、典型的なoperator ==の実装は、クラスのメンバーをすべて列挙して比較していくようなものになる。メンバーを手で列挙していくのは甚だ面倒である。コンパイル時に、クラスのメンバーを列挙し、それに対して操作を加えるようなリフレクション機能が必要である。

2. 型形成

利用例としては、たとえば、構造体の配列ではなく、配列の構造体を生成できる機能。

配列の構造体

ベクトル処理が一般的になる今日では、データ構造の配置が重要になる。例えば、「構造体の配列」は、ベクトル操作のためには非効率的なレイアウトとなる。効率のためには、「配列の構造体」が望ましい。

struct S
{
    int a ;
    int b ;
    int c ;
} ;

// 非効率的な「構造体の配列」
S a[100] ;

// 効率的な「配列の構造体」
struct SoA_vector_of_S {
    std::vector<int> as;
    std::vector<int> bs;
    std::vector<int> cs;
} ;

ベクトル処理では、このように、要素を連続したストレージ上にまとめることで、効率的に処理できる。しかし、このような「配列の構造体」を手で書くのは面倒だ。コンパイル時にこのような配列の構造体を生成できるリフレクション機能が必要である。

3. コンパイル時の文脈情報

assertは、極めて醜悪なCプリプロセッサーマクロで実装されている。assertだけではない。assertに有益な情報(ソースコードのファイル名や、行番号など)を渡すためには、これまたCプリプロセッサーである、 __FILE__や__LINE__といったマクロに頼らなければならない。

コンパイル時に、このような文脈情報を取得するリフレクション機能が必要である。

4. その他のエンティティの情報の列挙

クラスメンバーに限らず、列挙したい情報はいくらでもある。例えば、

  • namespace内の型
  • 関数の仮引数
  • namespace内のグローバル変数
  • enumの列挙子

コンパイル時に、このような情報を列挙できるリフレクション機能が必要である。

以上、これから議論して設計し、C++に提案するコンパイル時リフレクションは、最低でもこの4つの利用例をカバーしなければならないと論文は述べる。

既存の実装として、Cプリプロセッサーを悪用して、4.の列挙機能を実装したライブラリが挙げられている。

C++11: Non-intrusive enum class with Reflection support using Metaprogramming - CodeProject

N3815: Enumerator List Property Queries

これもいわばリフレクション機能にあたるわけだがenumの列挙子の数、その名前、値を列挙できるライブラリの提案。

[PDFのような多様性はいらない] N3816: Polymorphic Memory Resources - r1

従来、STLではアロケーターはテンプレート実引数として渡すものであり、静的ポリモーフィズムしかサポートしていない。動的ポリモーフィズムなアロケーター指定、すなわち実行時にアロケーターを指定することを可能にするために、標準のアロケーターのベースクラスの提案。動的に指定したいアロケーターは、このベースクラスから派生して、virtual関数をオーバーライドすることで実装できる。

また、この提案では、アロケーターを定義するための新しいコンセプト(インターフェース)も定義されている。従来のヘンテコな設計のアロケーターではなく、もっとましなインターフェースになっている。

N3817: C++ Latches and Barriers

スレッドの実行を制御するためのライブラリ、latchとbarrirerの提案。ラッチは、ある操作が完了するまで、ひとつないしは複数のスレッドの実行をブロックする。バリアーはラッチに似ているが、再利用できる。

どうも、セマフォとも呼ばれているような概念のようだ。この命名はどうなのだろうか。バリアーというのは、まったく別の概念である、メモリバリアーと混同しやすい気がするのだが。

[Cプリプロセッサーと同じでいまいましいPDF] M3818: Centralized Defensive-Programming Support for Narrow Contracts (Revision 2)

防衛的プログラミングと称して、微妙に挙動の違うassertマクロを大量に提案。もちろんCプリプロセッサーで実装されている。クソだ。

筆者はCプリプロセッサーを使ういかなる提案にも反対する。

[論文がPDFで提供されているようでは、コンセプトもお先真っ暗だ] N3819: Concepts Lite Specification

コンパイル時に評価される値を使った軽量なコンセプトの提案

N3820: Working Draft, Technical Specification — Array Extensions

実行時サイズ配列とdynarrayのTR。ドラフト規格に文面が見当たらないと思ったら、TRで出るらしい。

1 comment:

Anonymous said...

std::arrayの多次元化は自分も考えたことあるんですけど、まじめに実装したらどうなるか楽しみです。

それと、いつも翻訳ありがとうございます。
毎回、楽しみにしています。