2017-10-27

C++標準化委員会の文書: P0009R4-P0237R9

2017年10月分の文書が公開された。この8ヶ月ほど、C++17参考書の執筆に注力していて文書のレビューを怠っていたが、さっくりと解説して、次はC++入門書の執筆に移りたい。

P0009R4: P0009r4 : Polymorphic Multidimensional Array Reference

改定に改定を重ねてわけのわからないことになっている連続したストレージに対して多次元配列風のアクセスを提供するラッパーライブラリ。もともとarray_viewだったが、今ではmdspanという一見してわけのわからない名前になっている。これは、viewという用語が適切ではないという違憲によって変更された。

もともとレイアウト指定はなかったのだが、レイアウト指定は絶対に必要だという違憲があって追加された。C/C++風の末尾の次元がメモリ上で連続しているレイアウトと、FORTAN風の先頭の次元がメモリ上で連続しているレイアウト、そして、subspanで一部を切り出したときにメモリが連続していないことを示すレイアウトがある。

割と一見してコードの意味がわからなくなりそうな設計をしている。

P0037R4: Fixed-Point Real Numbers

markdownで書かれている。ほー、いいじゃないか。こういうのでいいんだよ。こういうので。焦るんじゃない。俺はPDFで読みたくないだけなんだ。

固定少数点数ライブラリfixed_point< Rep, Exponent>の提案。

fixed_point< uin32_t, -12 > a(1), b(2) ;

// 0.5
auto c = a / b ;

fixed_point<Rep, Exponent>の指数はpow(2, Exponent)となる。最小値はnumeric_limits<Rep>::min() * pow(2, Exponent)、最大値はnumeric_limits<Rep>::max() * pow(2, Exponent)

面白いことに、クラステンプレートのコンストラクターからの実引数推定と実引数推定ガイドを使った、初期化子の整数値からのExponentの推定機能がある。

auto a = fixed_point(0ul);
static_assert(is_same_v<decltype(a), fixed_point<unsigned long, 0>>);

Exponentは初期化子の整数値を表現できる最大の値が選ばれる。

また面白いことに、演算結果でRepやExponentが変わる。operator *ではRepが変わらないが、multiply/divideではRepも変わる。


// 安全に演算結果を表現できる型に変わる。
auto f = fixed_point<uint8_t, -4>{15.9375};
auto p = multiply(f, f);
// p === fixed_point<uint16_t, -8>{254.00390625}

// operator *だとRepが変わらない。
auto f = fixed_point<unsigned, -28>{15.9375};
auto p = f * f;
// p === fixed_point<unsigned, -56>{0}

// Repも変える
auto f = fixed_point<unsigned, -28>{15.9375};
auto p = multiply(f, f);
// p === fixed_point<uint64_t, -56>{254.00390625}

これは除算の場合も同じだ。


fixed_point< uint32_t, -16> a(1), b(2) ;
auto c = a / b ;
// c == fixed_point< uint32_t, 0>(0)

auto d = divide( a, b ) ;
// d == fixed_point<uint64_t, -32>(0.5) ;

Exponentの変化は、乗算の場合それぞれのExponentの加算、除算の場合は減算になる。

わかりやすいようなわかりにくいような。最悪の場合を想定しすぎなような。

exponentが小さくてもすむ型であれば最初から小さくしとけというのはわかるが、あまりにも目まぐるしくExponentが変わりすぎる。文書は組み込み型のDrop-in Replacementを意図して設計されているというが、以下の関数テンプレートに渡してエラーになるようなライブラリが本当にdrop-in replacementたりえるだろうか。

// 値を半分にして返す関数
template < typename T >
T half( T x )
{
    return x / T(2) ;
}

このコードは、どんなfixed_pointを渡しても、小数部が切り捨てられる。

P0096R5: Feature-testing recommendations for C++

機能テストマクロがC++17に対応。

P0124R4: Linux-Kernel Memory Model

Linuxカーネルのメモリーモデルの解説。

[PDF] P0196R4: Generic none() factories for Nullable types

ポインター、optionalなどnullableな型に使えるジェネリックなnone()の提案。

[PDF] P0201R2:A polymorphic value-type for C++

polymorphic_value<T>の提案。コピー時にT型を基本クラスとするpolymorphic typeをディープコピーしてくれるクラス。ディープコピーをするためにT型は何か特別なclone関数を用意する必要はない。


struct Base { int x ; } ;
struct Derived : Base { int y ; } ;

polymorphic_value p1( new Derived ) ;

// 値がディープコピーされる
polymorphic_value p2 = p1 ;
// Derivedのデストラクターが呼ばれる

アロケーターの指定がないのはなぜだろう。

P0202R2: A Proposal to Add Constexpr Modifiers to Functions in <algorithm> and <utility> Headers

algorithmとutilityをconstexprにする提案。

前の提案はcstring(主にmemmove/memset/memcmp)もconstexprにする提案だったが、cstringに手を入れるのは見送られた。かわりに、compiler intrinsicsなどの方法で実現する方向に調整された。

さて、既存のC++標準ライブラリの実装を見てみると、libstdc++はcompiler intrinsicsを使っているのでこのままconstexprに対応可能で、libc++はcstringを使っているので書き換えが必要だ。また、libc++はgotoを使っているのでこの点でも書き換えが必要となる。

stable_partition, inplace_merge, stable_sortは、メモリ確保、placement newによる構築、unique_ptrの使用があるので、constexprからは除外する。

shuffleとsampleはuniform_int_distributionを使うため、constexprからは除外する。

[PDF] P0214R6: Data-Parallel Vector Types & Operations

SIMDプログラミングのためのベクトル型の提案。なんだかすごく使いづらそうな設計だ。

[PDF] P0233R6: Hazard Pointers: Safe Reclamation for Optimistic Concurrency

ハザードポインターライブラリの提案。ハザードポインターはIBMのMaged M. Michaelによって考案され、IBMのMaged M. Michaelによって特許申請された。最終的に特許申請は取り下げられた。ところでこの提案文書の執筆者はIBMのMaged M. Michaelである。この提案が特許汚染されていないかどうか注意深い検証が必要だ。

ISO国際標準規格には特許汚染された技術を持ち込むべきではない。ましてや特許汚染の前科がある人間によって提案された機能は眉に唾をつけてみるべきだ。

[PDF] P0237R9: Wording for fundamental bit manipulation utilities

Nビットの符号なし整数型をN個のbit要素が入っているコンテナーだとみなし、ビットに対するイテレーターを提供するイテレーターアダプターライブラリ、bit_iteratorの提案。

ドワンゴ広告

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

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

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

No comments: