2017-12-06

C++標準化委員会の文書: P0790R0-P0799R0

P0790R0: library-operator-spaceship

operator <=>が標準ライブラリに与える影響について。

operator <=>によって生成される比較演算子は、ソースコードの書き換えと同等の効果を及ぼすのであって、実際の比較演算子ではないため、アドレスを取ることができない。これにより、opeartor <=>アドレスを取るユーザーコードは動かなくなる。これは互換性の問題となるが、そもそも比較演算子のアドレスを取るユーザーコードはまれだ。というのも、比較演算子はメンバー関数とフリー関数のいずれかで実装されるので、ユーザーコードでアドレスを取るにはどちらで実装されているか知らなければならない。また、一部の標準ライブラリは、a @ bのような式が妥当だとのみ規定されていて、operator @がどのように実装されているかを規定していない。その場合、ユーザーコードでアドレスを取った場合、そもそも未定義となる。なので、互換性の問題はまれにしか起こらないはずだ。

文書は、標準ライブラリで比較可能な型のうち、operator <=>に対応すべきではない型、変換関数を捨ててopeartor <=>に切り替えるべき型、既存の比較演算子に加えてoperator <=>を追加したほうがよい型、operator <=>を追加したほうがよい他の型をラップしている型、現在比較を提供していないがoperator <=>に対応したほうがよい型、operatgor <=>を追加したほうがよいCの型を列挙している。

valarrayというだいぶ忘れ去られた型も考慮している。

よく調べたものだ。

[PDF] P0791R0: Concepts are Adjectives, not Nouns

コンセプトCを使うtemplate < C X >を、template < C typename X >に変える提案。

template < C X >の意味はわからない。Xは型なのだろうか。値なのだろうか。CがコンセプトならばXは型だが、Cがintへのtypedef名ならば、Xは値だ。この問題は、内側のスコープの宣言で名前が隠れるともっとややこしくなる。


template < typename T > concept C = true ;

// Xは型
template < C X > struct S ;

namespace ns {

using C = int ;

// Xは値
template < C X > struct S ;
}

字面は同じtemplate < C X >なのに意味が変わってしまう。

この問題は、本来形容詞であるコンセプトを名詞として使っているから生じるのであって、形容詞的な文法にすればいい。すなわち、文法を以下のように変更する。

template < CopyConstructible typename T > struct S ;

この変更により、複数のコンセプトを簡単な文法で指定することも可能になる。

template < CopyConstructible LessThanCompareble tyepname T > struct S ;

なるほど、趣旨はわかるが文法が冗長になる。

P0792R0: function_ref: a non-owning reference to a Callable

Callableを所有しないラッパーfunction_refの追加。std::functionと違いメモリ確保をせず例外も投げない。

[PDF] P0793R0: SG5: Transactional Memory (TM) Meeting Minutes 2017/06/19-2017/10/09

Transactional Memoryの会議の議事録。

[PDF] P0794R0: SG14: Low Latency Meeting Minutes 2017/08/09-2017/10/11/

Low Latency会議の議事録。

[PDF] P0795R0: From Vulkan with love: a plea to reconsider the Module Keyword to be contextual

Vulkanより愛をこめて。

モジュールTSではmoduleというキーワードの追加を提案しているが、moduleという識別子はすでに多くの既存のソースコードで使われている。特にKhronos Groupの低級グラフィックAPIのVulkanでもmoduleを識別子として使っている。moduleは文脈依存キーワードにすべき。

[PDF] P0796R0: Supporting Heterogeneous & Distributed Computing Through Affinity

NUMAが当然となった現代では、メモリーアフィニティの重要性はいよいよ増すばかりだ。複数のスレッドによる並列処理を行ったとしても、そのメモリーが特定のひとつのスレッドだけで効率的にアクセスできるようになっている場合、並列処理はスケールしない。このようなメモリーとスレッドの関係をアフィニティと呼ぶ。

そこで、C++は標準でシステムのリソーストポロジーをクエリーし、メモリー領域の相対的なアフィニティをクエリー子、実行とメモリ領域を制限するようなアフィニティの設定機能を持つべきだ。

そんなの標準化できるのだろうか。

[PDF] P0797R0: Exception Handling in Parallel STL Algorithms

並列アルゴリズムを中断する方法の提案。

シーケンシャルアルゴリズムは例外を投げることによって中断できた。並列アルゴリズムも提案段階ではexception_ptrを複数もつexception_listを例外として投げることで中断できる予定だったが、この設計には色々と問題があったので廃止された。

この提案では、例外を格納するdisappointment_buffer<disappointment_type>を追加し、これを実行ポリシーオブジェクトで並列アルゴリズムに渡すことで例外リストを受け取る設計を提案している。

P0798R0: p0798r0: Monadic operations for std::optional

optionalにモナド操作として、and_then, or_else, mapを追加する提案。

画像から猫を抽出してより可愛くするコードを考える。

image get_cute_cat (const image& img) {
    return add_rainbow(
             make_smaller(
               make_eyes_sparkle(
                 add_bow_tie(
                   crop_to_cat(img))));
}

しかし、画像に猫が含まれていなかったらどうなるのだ。画像に蝶ネクタイを付加すべき場所が存在しなかったら、 猫が後ろを向いているので目を輝かすことができなかったら。それらの条件では、画像を返すことができない。

例外を使うというのも手だが、プログラムが画像を大量に処理するもので、画像に猫が含まれないことは例外的ではない場合、例外をコントロールフローに使うのはよろしくない。

そこでoptionalだ。

std::optional<image> get_cute_cat (const image& img) {
    auto cropped = crop_to_cat(img);
    if (!cropped) {
      return std::nullopt;
    }

    auto with_tie = add_bow_tie(*cropped);
    if (!with_tie) {
      return std::nullopt;
    }

    auto with_sparkles = make_eyes_sparkle(*with_tie);
    if (!with_sparkles) {
      return std::nullopt;
    }

    return add_rainbow(make_smaller(*with_sparkles));
}

しかし、こんなボイラープレートコードを書きたくない。

そこで、optionalのメンバーにmap, and_then, or_elseを追加すると、以下のように書ける。

std::optional<image> get_cute_cat (const image& img) {
    return crop_to_cat(img)
           .and_then(add_bow_tie)
           .and_then(make_eyes_sparkle)
           .map(make_smaller)
           .map(add_rainbow);
}

趣旨はわかるが現実の問題を解決するC++のコードが、そんなにきれいに引数をひとつ受け取ってひとつ返すような簡単なコードになるわけがなく、したがってこれを使おうとするとラムダ式で囲んだボイラープレートを書かねばならず、机上の空論に見える。

[PDF] P0799R0: Programming vulnerabilities for C++ (part of WG23 N0746)

C++標準規格の文面に脆弱性に対する忠告の文面を入れようという提案

ドワンゴ広告

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

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

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

5 comments:

Anonymous said...

モナドの話ですが、まさにユニファイドコールシンタックスの需要そのものじゃないですか。
コンセプトもテーブルに乗っかったという話ですし、復活考えてくれないかなぁ。とか。

Anonymous said...

別件ですが。
某5chの相談室で出てた話題です。
クラスの仮想関数を定義するとき、
virtual void F()=0;
などと書きますが、この0の意味が解らんということを話していました。
そこで話によると関数テーブルにNULLを代入しているという話が出てきました。
では、
virtual void F()=nullptr;
と書くことを躊躇する理由は無いと思いました。がエラーが出るそうです。
どうでしょうか、提案を書く気はありませんか?
まぁ、今更仮想関数を使うかどうかということはとりあえず置いておいて・・・。

江添亮 said...

たんにC++制定当時(80年台後半から90年代前半にかけて)、新しいキーワードを追加したくないという理由だけでその文法が選ばれた。何も代入しているわけではない。

Anonymous said...

そうですか。
まぁ、多少意味不明なところがあるので是正してほしいところです。
お時間いただきましてありがとうございました。

Anonymous said...

#define PURE = 0

virtual void F() PURE;

……というのをMSか何かがやってたはず。