2012-11-06

2012-11 post-Portland mailingの簡易レビュー

ISO/IEC JTC1/SC22/WG21 - Post-Portland mailing 2012-11

Post-Portland mailingが公開されている。最新のドラフトはN3485。今回はだいぶ変更が加えられているが、いずれも文面の修正や表現の統一 であり、極端な変更はないようだ。

今回は、ペーパーとしては公開されていない、会議前のペーパーに対する議論も紹介してみようかと思う。

N3386: Return type deduction for normal functionsには、少々の落とし穴もあるようだ。

再帰で戻り値の型を推測するには、型を推測できるreturn文が字句的に先行していなければならないそうだ。

存在を憂いていた、N3398: String Interoperationには、案の定、問題が噴出している。

結局、C++11でUTF-8リテラルを導入したのに、UTF-8型を導入しなかったのが問題なのだ。意見しても、C++の思想として、型は文字エンコードを表現しないという反論でそのままになった。

そしていま、UTF-8のライブラリ側での取り扱いをめぐって問題が起こっている。それみたことか。

実際、UTF-8リテラルと通常の文字列リテラルの型が同じだというのは、非常に問題がある。たとえば、UTF-8文字列リテラルを書こうとして、プレフィクスu8を書き忘れてしまったならば、通常の文字列リテラルとしてエンコードされてしまうが、その問題はコンパイル時に検出できない。同じ型だからだ。UTF-8文字は独自の組み込み型を与えられてしかるべきだったのだ。

std::stringは暗黙にUTF-8とみなしていいんじゃないというぶっきらぼうな意見まで飛び出す始末。その方が楽になるのだが。

N3405: Template Tidbitsも、注目していた。

template < typename T t >

というテンプレート仮引数の宣言で、任意の型の非型テンプレート実引数を受け取れるようにしようという提案である。

議論の結果、コンパイラー開発者から、elaborated type specifierと文法が曖昧になる問題を指摘された。解決には文法の変更が必要になる。

会議の場で仮に提案された文法は、

template <auto<class T> T n>

というものだが、これは見た目に分かりにくい。ただし、非型とその型の仮引数名を記述できる。

別の提案としては、

template <auto m>

というものがある。これは見た目に簡単だが、これで名前を付けられるのは非型だけで、非型の型を得るには、メタ関数を使わなければならない。

どちらも一長一短で賛成しがたい。さらなる議論と発想が必要であると思う。

N3444: Relaxing syntactic constraints on constexpr functionsはどうか。

「許可されている機能のリストなどというのは気に食わない。costexpr関数でもループ構文が使えるべきだ」などという主張もなされた。Stroustrupなどは慎重派で、現行のconstexpr関数の制限を緩めるには、相当の理由を提示すべきだと主張した。そこで、いろいろな利用例や具体的なコードが示された。結論としては、少なくとも提案されているだけの制限の緩和はするべきだろうという意見になった。

N3332N3329のstatic ifであるが、Stroustrupは導入に慎重なのが以外だった。問題は、static ifのような簡単なコンパイル時条件分岐を導入してしまうと、必要以上に多用されるだろうということだ。それでも、現行のテンプレートメタプログラミングよりは簡単で、メタプログラミングの門戸を開くことにつながるだろうという肯定的な意見も出た。

モジュールについては、現行のドラフトを元に、Clangで実装が進められているとのこと。

特に興味深いものだけを取り上げたが、これ以外の本の虫: 2012-09 pre-Portland mailingのあまり簡易ではないレビューで取り上げたペーパーについて、会議の概要を知りたい人は、知らせてくれればあとで書く。

さて、今回のペーパーの簡易レビューといこう。

N3456: Range arguments for container constructors and methods, with wording

Range復活。

皆が待ち望んでいたあのRangeが戻ってきた。コンセプトなしの提案だ。

RangeがC++11に導入されなかったのは悲劇だった。もちろん、あのままコンセプトを取り入れていても、取り返しのつかない問題になっただろうが。

もっとも、規格に入るのはRangeという要求だけで、BoostにあるようなRange adaptorは入らない。しかし、Range adaptorとともに使うこともできる。ペーパーでも強調して使うことが想定されている。

N3457: Algorithm std::iota and its modifications.

ひどいHTMLコードを見た。まあ、メールでのやりとりをそのままペーパーにしたので、メールを正しく表現するには当然pre要素を使うべきなのだろうが、しかしこれは・・・。

まあともかく、内容は、std::iotaを変更するというものだ。すでにあるstd::fillのスタイルに合わせて、iotaを似せるべく変更する。

しかし、くどいようだが、iotaは名前が符丁のようでわかりにくい。このようなギーク的な命名はどうかと思う。それこそ、incremental_fillとでもしておけばよかったのではないか。私は、タイプ数を減らすよりも分かりやすい名前を好む。まあ、今更言っても始まらない。

N3458: Simple Database Integration in C++11

PDFは死滅せよ。

既存のデーターベース操作のAPIは非常に汚い。たとえば、以下はODBCのコード片である。

SQLHandle statement ;
SQLAllocHandle (SQL_HANDLE_STMT, cconnection ,& statement ) ;
SQLPrepare ( statement , " select a , b from foo where c=? and d=?" , 38 ) ;
SQLLen len1 =3;
SQLBindParameter ( statement , 1 ,SQL_PARAM_INPUT,SQL_C_CHAR,SQL_VARCHAR, len1 , 0 ,
    " foo " , len1 ,&len1 ) ;
SQLINTEGER val =1234; SQLLen len2=sizeof( val ) ;
SQLBindParameter ( statement , 2 ,SQL_PARAM_INPUT,SQL_C_SLONG, SQL_INTEGER, len2 , 0 ,
    &val , len3 ,& len2 ) ;
SQLExecute ( statement ) ;
while ( SQLFetch ( statement )==SQL_SUCCESS) {
    double a , b ;
    SQLGetData ( statement , 1 ,SQL_C_DOUBLE,&a , 0 , 0 ) ;
    SQLGetData ( statement , 2 ,SQL_C_DOUBLE,&b , 0 , 0 ) ;
    cout << a << " " << b << endl ;
}

なんとも残念なコードではないか。ODBCはC bindingであるために、多くのボイラープレートなコードを必要とする。さらに、データベースのインターフェースは、関数呼び出しとして提供されている。さらに、コードは動的片付けであり、コードとクエリー結果の結びつきも貧弱である。

そこで、もっとC++らしいAPIを提案する。提案では、上記と同等のコードが、以下のように書ける。

prepared_query ps=conn.prepare_query( " select a , b from foo
    where c=? and d=?" ) ;
double a , b ;
for ( auto row : ps ( " foo " , 1234 ).into ( a , b ) )
cout << a << " " << b << endl ;

何とすばらしく簡潔に書けることか。

N3459: Database Access Comparison

実際にアメリカで使われている郵便システム(オラクルのproprietaryな言語であるPL/SQLで書かれている)のコード片を、C++で提案されているデータベースライブラリで書き換えた例。実際のコードは原文を参照すること。

不自由なプログラミング言語はけしからん。

N3462: std::result_of and SFINAE

std::result_ofをSFINAEでも引っかかるようにする改良。詳細は前回解説した。

N3463: Portable Source Files

以下の内容のソースファイルには、移植性の問題がある。

int main() { }

なぜか。それは、ソースファイルの文字のエンコードが規定されていないからである。そのため、このソースファイルをあらゆる環境でコンパイルするためには、環境に合わせたエンコードの変換を行う必要がある。

このために、Boostのソースファイルは、いまだに©などの文字を使えないし、開発者の名前も正しく表記できない。

のみならず、環境が対応していない可能性のある文字は、ユニバーサル文字や代替文字やトライグラフを使わなければ、新に移植性の高いソースファイルとはいえない。

いいかげんにせい、もう2012年なのだUTF-8エンコードされたソースファイルへの対応は義務である。

というわけで、C++1yの実装は、少なくともUTF-8エンコードのソースファイルを受け付けなければならないようにしようという提案。

これは至極当然の提案だ。

また、バイトオーダーマーカーである0xEFBBBFも受け付けることを義務付ける。Unicode Technical Committeeは、「0xEFBBBFバイトオーダーマーカーの有無は規格準拠のUTF-8であるかどうかの判断に左右しない」と言っている。しかし、0xEFBBBFは空白文字なのだから、真にUTF-8対応のソフトウェアは、空白文字として扱うべきなのだ。

N3465: Adding heterogeneous comparison lookup to associative containers for TR2 (Rev 2)

すまん、よく分からん。

内容としては、2001年にDave AbrahamsがN1313: Binary Search with Heterogeneous Comparisonで提起した問題が、連想コンテナではいまだに修正されていないので、修正するというものだ。

その問題というが、残念ながら数学的にチャレンジドな私の頭では理解できない。いわゆる比較関数がstrict weak orderingかどうかという問題なのだが。

N3466: More Perfect Forwarding

threadやbindは、実引数をリファレンスで取らない。

void f(int &i) { i = 2; /* ... */ }
int i;
f(i); // iはリファレンスで渡される
thread tf = thread(f, i); // iはリファレンスで渡されない

これは、テンプレートの実引数推定がそうなっているためだ。

しかし、だからといって単にthreadやbindの実引数をrvalueリファレンスで取ればいいというものではない。取ったとしても、正しくforwardingできないのだ。関数オブジェクトの仮引数の型を取得する方法がないからだ。

そのため、仮引数の型を取得できるコンパイラーの支援のメタ関数、std::signatureを追加する提案。

これはいわゆるコンパイル時リフレクションの一種だ。よりパーフェクトなforwardingができるようになる。

N3467: Runtime-sized arrays with automatic storage duration

動的に大きさを指定できるautomatic storage durationの配列を追加する提案の改良案。

細かい変更に留まるので特に説明しない。ヒープ上に構築できるようになったのは大きいかもしれない。もっとも、見逃していただけなのだが。

N3468: User-defined Literals for Standard Library Types (version 2)

標準ライブラリにユーザー定義リテラルを追加しようという提案の改訂版。

さすがに、二進数リテラルをユーザー定義リテラルというライブラリとして提供するという提案は、コア言語の領域だということで、コア言語グループに投げられた。また、コンパイル時atoiとして提供するという代わりの提案も却下された。汎用的なコンパイル時atoiなど提供できるわけがない、というのがその理由だ。

Constexpr Library Additions v3: chrono
Constexpr Library Additions v2: containers
Constexpr Library Additions v3: utilities

既存の標準ライブラリをconstexpr対応にする些細な変更。

N3472: Binary Literals in the C++ Core Language

PDFは死滅せよ。

コア言語で二進数リテラルを追加する提案。プレフィクスは0b/0Bになる予定。すでにGCCやClangで拡張機能として実装されており、またJavaやDなどといった他の言語でも実装されているので、実装経験は豊富であり、入るとすれば問題なく入るだろう。

数値リテラルのセパレーターについては、この提案では考慮せず、別の独立した議論である。

N3477: C++ Internet Protocol Classes

PDFは早く死ね。

もはや、C++にも標準のネットワークライブラリを考慮しなければならない時代になっている。この提案では、ネットワークの中でインターネットを取り上げ、その中でも特に、IPアドレスに関するライブラリについて提案している。このライブラリの設計は、有名な既存のネットワークライブラリであるPOCOを元にしている。

N3478: Core Issue 1512: Pointer comparison vs qualification conversions

この提案では、ポインターの比較について変更を加える。

提案では、以下のコードをill-formedにする。

void f(char * p)
{
  if (p > 0) { ... }
  if (p > nullptr) { ... }
}

また、以下のコードはwell-formedにする。

void g(int **p1, const int**p2)
{
   if (p1 == p2) { ... }
}

N3479: Priority Queue, Queue and Stack: Changes and Additions

PDFは滅せよ。

std::priority_queueの改良案。実装のオプションをコンパイル時にテンプレート実引数として指定できる。

イテレーター、値の変更、マージの効率化、安定ソート、比較。

N3484: A URI Library for C++

C++標準のネットワークライブラリとして、URIに特化したライブラリの提案。

N3487: TLS and Parallelism

PDFで構築した視覚効果激しいプレゼン用の画面集をペーパーとして公開するのはやめようぜ。

TLS(Thread Local Storage)は、C++11にもthread_localというキーワードと、thread storage durationという形で取り込まれたが、この機能は現実の三種類の利用例に一致していない。三種類の利用例に一致するTLSを、言語なりライブラリなりで提供すべきであり、現行のthread_localは、この三種類のうちの利用例のどれかに一致するように変更しようという提案。

どうも中身がない気がする。

N3489 - A Rational Number Library for C++

C++に標準の有理数ライブラリを追加する提案の改訂版。議論の末、改良を加えた。

N3490: Controlling Argument-Dependent Lookup

title要素のないHTMLはill-formedでありけしからん。

これはDaveはんの提案なんやな。この人昔から、ADLを無効にする方法を追加しよう言うてはるんや。

この提案では、ADLを無効にする方法を追加する。特に、演算子以外のADLを向こうにする方法を追加する。ADLが最も必要とされるのは、グローバル以外の名前空間スコープの型に対する演算子のオーバーロードなのだから、演算子以外でADLを無効にする機能が欲しい。さらに、演算子も含めてADLを完全に無効にする機能も提案している。

さらに、一部の名前だけ、宣言されたスコープ内においてADLを有効にする機能も提案しているが、これはすでに用いられてきたusing宣言のトリックと非常によく似ている。

N3492: Use Cases for Compile-Time Reflection (Rev. 2)

外道祭文。PDF地獄。スカラカ、チャカポコチャカポコチャカポコチャカポコ。

コンパイル時リフレクションの利用例を紹介したペーパーの改訂版。さらに利用例が増えているようだ。

Serializationなどのリフレクションを必須とする利用例を始めとして、enumの情報取得や、デフォルト実引数の取得など、なにやら面白い利用例も上がっている。ある関数オブジェクトを完全にラップするためには、デフォルト実引数をコンパイル時に取得できることが必要になるのは、言われてみれば当然だが。

1 comment:

刈谷満 said...

std::iota の件のタイトル&リンクが range のやつになっちゃってますよ。