2014-08-08

2014-05-pre-Rapperswil-mailingのレビュー: N4040-N4051

[PDFとはお先真っ暗] N4040: Working Draft, C++ Extensions for Concepts

軽量コンセプトのドラフト文面案

Concerns with changing existing types in Technical Specifications

Issaquah会議で、TSはstd名前空間のライブラリを変更してよいと決定された。つまり、std::experimentalなどの実験的な別の名前空間の中にそっくりライブラリをコピーして変更し、またTSの文面もすべてをコピーした上で変更ではなく、TS文面は差分だけで良くなったし、std名前空間を直接書き換えてよくなった。

これは、色々と懸念事項もある。

ある実装がTSの実験的実装をしたとして、コンパイラーオプションなどで有効にできるようにしていたとする。TS機能を有効にした場合、ライブラリがABI互換性を静かに壊してしまう可能性がある。

また、std名前空間は標準ライブラリの実装にしか使う権利がないので、TSに完全準拠したサードパーティ実装ができなくなる。

TSの機能は、実際に実装されて、現実の利用者による利用経験が積まれなければ、規格に正式に取り入れるかどうかの判断ができない。

論文では、この懸念に対する明確な結論を出していない。

[PDFからまともなフォーマットへの安全な変換が望まれる] N4042: Safe conversions in unique_ptr<T[]>

現在、提案されているunique_ptr<T[]>は、派生クラスへのポインターから基本クラスへのポインターの変換は、危険なので禁止している。

struct base { } ;
struct derived { } ;

int main()
{
    // ill-formed
    std::unique_ptr<base[]> p( new derived[10] ) ;
}

しかし、この制限は強すぎて、以下のような安全な型変換も禁止してしまう。


unique_ptr< Foo const [] > ptr1( new Foo[10] ) ; // ill-formed
unique_ptr< Foo [] > ptr2( new Foo[10] ) ;
unique_ptr< Foo const [] > ptr3 = move( ptr2 ) ; // ill-formed
unique_ptr< Foo const [] > ptr4 ;
ptr4.reset( new Foo[10] ) ; // ill-formed

これは明らかに安全であるので、これは認めようという提案。

このような細かい条件でill-formedにするかどうかを切り替える方法には、static_assertを使う方法と、SFINAEを使う方法がある。static_assertはエラーメッセージも読みやすくはなるのだが、ハードエラーになってしまうという問題がある。そのため、論文では、規格の他の場面でもよく使われている、SFINAEによる方法を提案している。

この制限緩和は然るべきであると思う。

N4043: Dynarray Allocation Context

dynarrayで問題になったように、明示的なデストラクターの呼び出しとplacement newは問題になる。この論文はその問題に対処するために、デストラクター呼び出しとplacement newで再構築されない自動ストレージに関しては、実装依存の最適化を許す文面を追加することで解決しようとしている。

そういうここからここまでは実装依存と定義するだけの簡単な問題ではないと思うのだが。

N4044: A Three-Class IP Address Proposal, Revision 1

IPアドレスを表現するライブラリの提案

前回の論文からの変更点で、特にある人物の興味を引きそうな変更:「多くの関数がnoeceptと指定された」

[またPDFだ] N4045: Library Foundations for Asynchronous Operations, Revision 2

コールバックとfutureの両モデルをサポートする設計の紹介論文。

[PDFで書かれた論文の価値は低い] N4046: Executors and Asynchronous Operations

タスク単位を自動的に並列実行してくれる並列実行ライブラリの論文。

[暗い未来を予感させるPDFフォーマット] N4047: A Module System for C++

#includeの代替機能、モジュールの提案。

C++にはライブラリをコンポーネント化する近代的な機能が欠けている。C++にあるのは、Cから受け継いた#includeである。#includeとは単なるテキストデータをその位置に挿入するものである。コンパイラーからしてみればコピペだ。

#includeはC++の長いビルド時間の原因にもなっている。#includeされるソースコードの意味は、すでに定義されているマクロによって変わるし、#includeの後に続くソースコードの意味も、#includeされるソースコードで定義されているマクロによって変わる。

C++には、もっと近代的なライブラリの分離のための機能が必要だ。その機能はモジュールと名付けられ、設計が進んでいる。

この論文の提案は、既存のプリプロセッサー自体には何も変更を加えない。過去に、プリプロセッサーに付け焼刃的な変更を加えて害悪を軽減しようという提案はいくつもあったが、どれも失敗に終わっている。ぷりプロセッサーには長い歴史があり、短期的に廃止できるものではない。したがって、新しい機能は、プリプロセッサーと共存しなければならない。

提案では、新しいキーワードとして、moduleとimportのふたつを追加する。

モジュールを使うソースコードは、モジュールをimportする。

// N4047提案
import std.vector ;

int main()
{
    std::vector<int> v ;
}

モジュールは、最初の宣言でモジュール名を宣言する

// N4047提案
module std.vector ;

export
{
// 外部に見せる名前の宣言
}

export { }で囲まない名前は、外部に公開されない。ローカルな定義になり、他の翻訳単位でその名前を使った定義があったとしても、ODR違反にはならない。

// 1.cpp
module one ;

export { void f() { } }

void g() { }
// 2.cpp
module two ;

export { void g() { } }

void f() { }
// main.cpp
import one ;
import two ;

int main()
{
    f() ; // oneのf
    g() ; // twoのg
}

この三つの翻訳単位からなるプログラムをコンパイルしてもODR違反とはならない。モジュールでは、export { ... } で囲んだ名前のみが外部に公開され、それ以外の名前は外部に公開されず、ODR違反にもならないようになるからだ。

モジュールは相互の参照もヘンテコな前方宣言なしに書くことができる。

// A.cpp
module A ;

export {

import B ;

class A
{
    B * ptr ;
} ;
}
// B.cpp
module B ;

export {
import A ;

class B
{
    A * ptr ;
} ;

}

早くモジュールが実用化されて欲しい。

[PDFも改良してほしい] N4048: More Improvements to std::future<T> - Revision 1

N3865の改訂版。optionalのより汎用なライブラリ、expectedに対応した変更があるようだ。

[無PDF原則も提案したいところ] N4049: 0-overhead-principle violations in exception handling

例外において、ゼロオーバーヘッドの原則が尊重されていない例の提示。

例外にはオーバーヘッドがある。標準ライブラリは例外に強く依存しているので、例外を使ったコードを吐く。また、生成されるコードも、例外に対応するためのバッファーなどを持っている。これらはたとえ例外を使わなかったとしてもメモリ使用量を増加させる。そして、既存のリンク時コード除去やLTOは、これらのコードやバッファーを取り除くほど賢くない。

GCCには例外を使わないオプション-fno-exceptionsがある。しかし、これはフロントエンドで例外を使わないという指定だけであって、ライブラリは依然として例外を使うし、バックエンドが吐くコードも、例外のコードを吐くし、例外をサポートするためのコードや、例外が緊急時に使うバッファーなども確保する。これらはメモリ使用料を増加させる。

これらのオーバーヘッドを取り除くにはツールチェインに手を入れて、本当に例外を使わないようにするしかない。

論文は、現時点でのGCCの実装を示して、問題提起をするだけで、何も結論を出していない。

N4050: Dynarray Semi-Editorial Issues

dynarrayに対する文面上の些細な修正。とはいっても、単なる文法ミスや誤字脱字よりはすこし真面目な問題を修正している。

N4051: Allow typename in a template template parameter

テンプレートテンプレートパラメーターにtypenameキーワードを利用できるようにする提案。

今までは、

// 現状
template < 
    template < typename T >
    class U // classキーワードが必要
    >
class C ;

このように、テンプレートテンプレートパラメーターは、文法上の制約でclassキーワードを使わなければならなかったが、この提案では、typenameキーワードも使えるようになる。

// N4051提案
template < 
    template < typename T >
    typename U // typenameキーワードが使える
    >
class C ;

些細な変更だが、プログラマーの無用の混乱を防ぐために、入って欲しい変更だ。

ちなみに、Clangが-std=c++1zでN4051提案の実験的実装をしている。

Clang - C++1z, C++14, C++11 and C++98 Status

これで、2014年5月分の論文集が終わった。次は7月分だ。

ドワンゴ広告

この記事はドワンゴ勤務中に書かれた。

来週は遠慮無く有給休暇を取ったので丸々休みだ。久しぶりに京都に帰省する。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

3 comments:

Anonymous said...

> これらはメモリ使用料を増加させる。

カネが多く必要ですね?

Anonymous said...

importよいですね。
自分の範囲ではVCですけどまぁそんな遅くはないですが、ヘッダーに分ける作業がめんどくさいので1ファイルで完結してほしいというのが本音です。import期待です。

mmYYmmdd said...

N4051に関して。
N4070-N4079の記事に対して書いたコメントと関連しますが、変数テンプレートを受け取るために、
template <template <typename...> T t>
みたいな文法は必要ないでしょうか?