本の虫

著者:江添亮
ブログ: http://cpplover.blogspot.jp/
メール: boostcpp@gmail.com
Twitter: https://twitter.com/EzoeRyou
GitHub: https://github.com/EzoeRyou

アマゾンの江添のほしい物リストを著者に送るとブログ記事のネタになる

筆者にブログのネタになる品物を直接送りたい場合、住所をメールで質問してください。

C++標準化委員会の文書: P0403R0-P0418R1

P0403R0: Literal suffixes for basic_string_view

string_viewに対するユーザー定義リテラル、svの提案。

std::string_view s = "hello"sv ;

P0406R1: Intrusive Containers

タイトル通り、Intrusiveコンテナーを追加する提案。BoostのIntrusive Containersを土台にしているが、だいぶ簡略化している。

要素型のIntrusiveコンテナーへの対応方法として、Base hookしか提供しない。要素型は、container_name_element(boostならばcontainer_name_base_hookであったもの)を派生することによってIntrusiveコンテナーに対応できる。

Boostにあるauto linkとsafe mode機能は提供しない。

現在標準ライブラリにあるコンテナーに相当するものだけを追加する。つまり、list, forward_list, set, multiset, unordered_set, unordered_multisetだ。メンバーも現行の標準ライブラリのコンテナーにあるものだけを提供する。Boostのようなアルゴリズムやデータ構造が固定された具体的なコンテナーやリッチなメンバーは提供しない。

あれば便利だろう。

P0409R1: Allow lambda capture [=, this]

ラムダ式のデフォルトキャプチャーに=が書かれた場合でも、thisを書けるようにする提案。わかりやすさのために。

P0412R0: Benchmarking Primitives

ベンチマーク用に最適化を抑制するライブラリの提案。

あるコード辺の処理時間を計測するには、以下のようなコードを書く。

auto start = chrono::high_resolution_clock::now();
double answer = perform_computation(42);
auto delta = chrono::high_resolution_clock::now() - start;

問題は、コンパイラーは最適化によってこのベンチマークを意味のないものにしてしまう。関数に渡した値はコンパイル時に計算できるので、コンパイラーは処理をコンパイル時に済ませてしまうかもしれない。また、結果であるanswerが出力に使われていないので、コンパイラーは処理をまるごと消してしまうかもしれない。

さらに、C++規格上、コンパイラーが処理を以下のような順番に並び替えてもよい。

double answer = perform_computation(42);
auto start = chrono::high_resolution_clock::now();
auto delta = chrono::high_resolution_clock::now() - start;

P0409R0では、この問題に対処するため、時間フェンスが提案された。timing_fence()を呼び出すとその前後の処理がリオーダーされないことを保証する。しかし、時間フェンスはコンパイラー実装者によって、実装不可能だと回答された。

そこで、この提案では、最適化阻害のための擬似IOライブラリを提案している。

namespace std {
namespace experimental {
namespace benchmark {

template<class T>
void keep(T &&) noexcept;

template<class T>
void touch(T &) noexcept;

} } }

keepは、実引数に渡されたオブジェクトの内部表現のバイト列を、あたかも(as-if)何らかのデバイスに出力したかのように振る舞う。

touchは、実引数に指定されたオブジェクトの内部表現のバイト列を、あたかも(as-if)何らかのデバイスから入力を得てきたかのように振る舞う。

これにより、C++実装はコンパイル時に値を推定して最適化することができなくなる。

auto start = chrono::high_resolution_clock::now();
int value = 42;
experimental::benchmark::touch(value);
double answer = perform_computation(value);
experimental::benchmark::keep(answer);
auto delta = chrono::high_resolution_clock::now() - start;

実装可能なライブラリとしては簡単だが、使いづらそうだ。漏れがあると最適化がかかってしまう。

P0414R1: Merging shared_ptr changes from Library Fundamentals to C++17

shared_ptrを配列に対応させる変更をLibrary Fundamentals TSから切り離して単独でC++17に追加。

P0415R0: Constexpr for std::complex

std::complexをconstexprに対応させる提案。コンストラクターがconstexprになるのでリテラル型となりconstexpr変数として使うことができるが、演算はconstexprに対応しない。

libstdc++は、std::complexの実装にコンパイラーマジックである__complex__を使っていて、これはコンパイル時定数として扱える。

libc++は、純粋にライブラリとして実装している。<cmath>に依存しているため、演算をconstexpr化できない。

[PDF] P0416R1: Operator Dot (R3)

operator .をオーバーロードできるようにする提案。

目的は、スマートリファレンスを実装できるようにするため。ただし、operator .のオーバーロードを実現するために挙動がとても不可解になっており、理解不可能なほどクソになっている。

こんなクソな提案が行われているのは、これがBjarne Stroustrupのお気に入りの提案だからだろう。Bjarne Stroustrupはもはや現代のC++の発展のために害悪ではないかと思う。Bjarne Stroustrupが関わった最近の機能はだいたい失敗している気がする。コンセプトしかり、dynarryしかり。

P0418R1: P0418r1: Fail or succeed: there is no atomic lattice

言語法家の熾烈な争い。

atomic操作のcompare_exchangeに渡すメモリーオーダー引数、successとfailureについて、規格は、「failure引数はsuccess引数より強くてはならない」としている。この「より強く」とはどのような意味か。規格は「より強く」を定義していない。メモリーオーダー同士を比較してより強いかどうかを判断するための半順序をC++規格は規定すべきだ。

これを受けて、Urbana会議で、relaxedが一番弱く、set_cstが一番強く、その間にいろいろと半順序でメモリーオーダーが入る、以下のようなメモリーオーダーの束を規定した。

relaxed release consume acquire acq_rel seq_cst

しかし、メモリーオーダーの束を規定するこの修正案には問題がある。releaaseとconsume/acquireの間には順序がないが、どのように解釈すればいいのか。そもそもsuccessとfailureにこのような制約を設けることに意味はあるのか。ロードとストアがそれぞれ単独の命令であるようなアーキテクチャでは、命令ごとにメモリーオーダーも異なるわけだ。

そこで、最終的な修正案では、このような制約自体をなくすことにした。これにより、メモリーオーダー同士の束を規定する必要もなくなった。

ドワンゴ広告

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

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

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