2014-01-pre-Issaquah mailingのレビュー: N3880-N3889
[なかなか悪くないHTML] N3880: Improving the Verification of C++ Programs
ようやく、C++論文で許せるマークアップのHTMLを読んだ気がする。
この論文は、C++にプログラムの検証を支援するための機能の必要性を提案している。
プロジェクトを始めるにあたって、どのプログラミング言語を選ぶかということは重要である。プログラミング言語ごとに利点や欠点があるので、考慮される。考慮に上がる対象に、検証可能性は重い。標準規格に、検証のための標準の規格がないのは、C++の利用を妨げる要因となっている。
この論文は、検証を標準規格でサポートするための必要性を提起するものであり、具体的な新機能の提案は含まれていない。ただし、現在のC++で改良できる分野として、いくつかの点を上げている。
たとえば、static_assertのメッセージを改良するだとか、API設計の妥当性を検証するためにコンパイルエラー自体をテストする機能であるとか、ill-formedの詳細な分類とか、文脈に依存したソースコード上の情報を取得する機能(リフレクションなど)や、より高度なassertionライブラリ、テストの際にのみ実行されるコード片の登録機能、検証プログラムの自動生成、などを挙げている。
まだ、検証力の必要性の提起だけなので、具体的にどのような新機能が提案されるのか、また実装可能なのか、興味深くはある。
[PDFも修正されるべき] N3881: Fixing the specification of universal-character-names
UCNに関する訂正。
C++11では、Unicode文字はすべてPhase of Translationのできる限り早い段階でUCNに変換するなどという定義にしてしまったため、真面目に実装しようとすると、色々と問題が出てくる箇所がある。また、変換前のソースコードを再び読まなければならない時もある。未定義な挙動もある。
そのため、いままで規格がカバーしきれていなかった範囲の挙動まで詳細に指定する文面の変更を行う提案。
具体的にどのような問題があるかは、論文を参照。
[PDFも使いづらいという現状を認識すべき] N3882: An update to the preprocessor specification
これもN3881と似通った論文。
忌まわしき太古の遺物であるCプリプロセッサーには、未定義な挙動が多々ある。当時としては、実装の自由度を持たせるために適切であったことも、Cプリプロセッサーが十分に枯れ尽くした今となっては、異なる実装間の移植性を妨げるだけである。
それに、今の最新のコンパイラー(GCC 4.9, Clang 3.4, 不自由なMSVC 12, 不自由なEDG/ICC 13)を比較すれば、もはや挙動の差異は微々たるものである。
そこで、今までCプリプロセッサーで未定義の挙動とされていた部分を、今の有名な実装の挙動を追認する形で、規格で詳細に定義する提案。
具体的にどのような問題があるかは、論文を参照。No! You cant haz cheeze burger!
N3883: Code checkers & generators
コードチェッカーとジェネレーターというか、コンパイル時リフレクション機能の提案。
この論文が大雑把に提案している機能は、コンパイル時に、コンパイラーのASTの一部をC++ユーザーに提供し、また生成する力を与えようというものである。
例えば、以下のようなクラスがあったとする。
// 人を表現するクラス
class Person
{
private :
std::string name ;
std::string address ;
double weight ;
// その他多くのデータメンバー
public :
// 比較関数の宣言
bool operator == ( Person const & rhs ) const ;
} ;
このクラスのoperator ==を実装したい。3個のデータメンバーがすべて等しければ等しいとみなすようにしよう。これは、以下のように書ける。
// 比較関数の定義
bool Person::operator == ( Person const & rhs ) const
{
return this->name == rhs.name &&
this->age == rhs.age &&
this->weight == rhs.weight &&
// その他のデータメンバーの比較
;
}
しかし、このようなコードを手書きするのは、間違いの元である。もしPersonの宣言を変更した場合、operator ==も変更しなければならない。またまた間違いの元である。このような機械的なコードは、自動生成したい。
それには、コンパイル時にクラスのメンバーという情報を取得し、また取得した情報に基づいてコードを生成する力が必要だ。すなわち、ASTの取得と改変能力が必要だ。
N3883提案は、そのような強力な力をC++に与える力強い提案である。
// ドライバー
class EqualityDriver
{
constexpr EqualityDriver(const ClassDecl & classDecl)
{
class_name = classDecl.getTypeName() ;
for ( auto & field : classDecl.fields( ) )
{
members.emplace_back( field.getName( ) );
}
}
meta::vector<meta::id_name> members;
meta::type_name class_name;
} ;
// 比較関数生成のためのパターン
$define OperatorEqGenerator( EqualityDriver driver )
{
bool $driver.class_name::operator==(const $driver.class_name & rhs) const
{
return true
$for (auto member : driver.members) {
&& $member == rhs.$member
}
;
}
}
// 比較関数の生成
$OperatorEqGenerator( Person ) ;
N3883提案は、$define, $use, $for, $if, $switchという新しいキーワードで、ASTを取得、あるいは改変する。
一度このような生成規則を書いてしまえば、あとは、全データメンバーを比較するあらゆるクラスに適用できる。
struct Foo
{
int x ;
int y ;
bool operator == ( Foo const & ) const ;
} ;
struct Bar
{
double d ;
bool b ;
bool operator == ( Bar const & ) const ;
} ;
$OperatorEqGenerator( Foo ) ;
$OperatorEqGenerator( Bar ) ;
いや、ちょっと待て。先ほどのクラスPersonだが、weightというデータメンバーの値は、比較の対象にならないようにできないのか。第一、人は体重が増減しても、同一人物ではないか。
もちろんできる。
// 体重を考慮しないドライバー
class EqualityDriver
{
constexpr EqualityDriver( const ClassDecl & classDecl )
{
class_name = classDecl.getTypeName();
for ( auto & field : classDecl.fields() )
{
// 特定の名前のデータメンバーをフィルターする
if ( field.getName() == "weight" )
continue ;
// 残りは追加。
members.emplace_back(field.getName());
}
}
meta::vector<meta::id_name> members;
meta::type_name class_name;
} ;
これぐらいたやすいことだ。そう、N3883提案ならば、C++はASTの一部に干渉できるのだ。
他にも、具体的なコード例は省略するが、構造体の配列を、構造体の各データメンバーの配列に変換したり、既存の関数を置き換えたり、文字列からenum型を生成したりと、やりたい放題だ。
そう、もはやCプリプロセッサーマクロは時代遅れの遺物になるのだ。これから#defineなどと書く幽霊プログラマーは、後ろ指をさされてひと目を忍んで地下に潜って、かつての混沌とした日々を懐かしむぐらいしかすることがなくなるであろう。$if, $else, $switchにより、従来のCプリプロセッサーマクロの役割は、完全に代替される。
そう、テンプレートメタプログラミングも時代遅れの遺物になる。もはやTMPでレイトレーシングをする岡山の陶芸家はお呼びではないのだ。
コンセプトですら、N3883により、改善される。
この提案は、AngularJSから影響を受けており、またその設計には、Clang APIをそのまま持ってきている。
唯一の不満点は、その文法が悲惨なことだ。$はPHPを彷彿とさせるものがある。
文法に議論の余地はあるものの、このような提案は、さらに発展させるべきだ。
[PDFも一新されるべき] N3884: Contiguous Iterators: A Refinement of Random Access Iterators
Contiguous Iteratorという概念を標準ライブラリに追加する提案。
Contiguous Iteratorとは、連続したストレージ上に確保されている要素の集合を指し示すイテレーターであることを保証するものである。
つまり、以下のようなことが保証される。
// Contiguous Iteratorの例
template < typename contiguous_iterator >
void f( contiguous_iterator iter )
{
auto next = iter + 1 ;
&*iter + 1 == &*next ; // true
}
つまり、イテレーターの指し示すオブジェクトのポインターを+1した結果のポインターと、イテレーターを+1した結果のイテレーターの指ししめすオブジェクトのポインターが、等しいことが保証される。
これは、たとえばC時代のAPIにポインターを渡すとか、連続したメモリであることを検出してmemcpyに切り替えるなどのアルゴリズムの最適化など、連続したストレージ上に確保されていることが保証されていることを利用したコードが書けることを意味する。
[PDFを廃止する提案] N3886: A Proposal to add a Database Access Layer to the Standard Library
データベースアクセスのためのインターフェース的なライブラリを標準ライブラリに追加する提案。
論文には、具体的なインターフェースの設計が書かれているので、興味のある人は呼んでもらいたい。このブログにコピペして解説することはしない。
インターフェースの設計は、バックエンドのデータベースとして、SQLベースのリレーショナルデータベースを想定している。
このような共通のインターフェースを標準化する理由としては、データベースアクセスのためのAPIは、実に多数あり、しかもその多くが、大昔のCの設計になっている。モダンなC++風の洗練されたインターフェース設計のライブラリが存在するべきである。
[一貫性のために論文フォーマットとしてPDFを廃止せよ] N3887: Consistent Metafunction Aliases
[PDF注意] N3655で、ほとんどのメタ関数には、エイリアステンプレートを用いて、metafunction_tが作られたが、tuple_elementだけは欠けていた。そのため、tuple_element_tを付け加える提案。
また、すべてのメタ関数にそのようなエイリアスが必要というわけではない。そのようなエイリアスが必要もないメタ関数だってある。そのため、いつ_tにすべきかという今のガイドラインは、あまりにも範囲が広すぎるという議論もしている。
[PDFで公開するようでは、お先真っ暗] N3888: A Proposal to Add 2D Graphics Rendering and Display to C++
2Dグラフィック描画ライブラリをC++に付け加える提案。
なぜ必要なのかという理由から始まって、グラフィック関連の様々な事情を説明している、結構長い論文。これはいずれ、別の記事で詳しく紹介したい。
今の予定では、土台としてcairoを用い、C言語によるインターフェースに、機械的な変換ルールを定義して、C++風のインターフェースに書き換えるようにしている。
その変換ルールも提案している。
[高濃度のPDF汚染を検出] N3889: Concepts Lite Specification
Concept Liteの仕様書案
ドワンゴ広告
この記事は、ドワンゴに昼過ぎに出社してボードゲームをやる合間に書いた。
ドワンゴは本物のC++プログラマーを募集しています。
CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0