本の虫

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

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

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

C++標準化委員会の2018サンディエゴ会議の結果

2018 San Diego ISO C++ Committee Trip Report (Ranges v1 TS for C++20; consensus on modules design; new Language and Library Evolution Incubators) : cpp

2018年サンディエゴ会議のトリップリポートが公開されている。今回も大きく変わった。

Range

Rangeが入った。Rangeは膨大なのでここでは解説しない。

Yet another approach for constrained declarations

autoと書くべきところをCocept autoと書けるようになった。


template <auto N >
auto f( auto x )
{
    auto y = x ;
}

というコードを、


template < Concept auto N >
Concept auto f( Concept auto x )
{
    Concept auto y = x ;
}

と書ける。

関数の戻り値の型と変数宣言の場合はautoを省略できる。


template < Concept auto N >
Concept f( Concept auto x )
{
    Concept y = x ;
}

こんなところがまだ変わるようでは、まだまだC++20参考書は書けそうにない。書いたそばから変わっていく。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1073r2.html

必ずコンパイル時に評価されるconsteval関数が追加された。

consteval int f( int x )
{
    return x+1 ;
}

constexpr関数は実行時評価でよい場合は評価を実行時に遅延させてもよいという規定がある。consteval関数は必ずコンパイル時に評価される。

std::is_constant_evaluated

コンパイル時評価されているときにtrueを返すstd::is_constant_evaluatedを追加する。


constexpr double power(double b, int x) {
  if (std::is_constant_evaluated() && x >= 0) {
    // A constant-evaluation context: Use a
    // constexpr-friendly algorithm.
    double r = 1.0, p = b;
    unsigned u = (unsigned)x;
    while (u != 0) {
      if (u & 1) r *= p;
      u /= 2;
      p *= p;
    }
    return r;
  } else {
    // Let the code generator figure it out.
    return std::pow(b, (double)x);
  }
}

これにより、constexpr関数の中にコンパイル時処理と実行時処理を同時に書くことができるようになる。

少し異質なライブラリで、コンパイラーマジックでサポートされるので、ヘッダーファイルに依存せず使うことが可能となっている。

[C++標準化委員でなければ読めない] p1330r0.pdf

unionの有効なメンバーを切り替える処理をコンパイル時定数にする。std::stringやstd::optionalをconstexpr化するのに必要。

p1002r0.pdf

try, catchをコンパイル時処理では無視する。コンパイル時定数への対応ではない。標準ライブラリの多くをconstexpr化するのに必要。将来的に例外をコンパイル時定数に対応する可能性を閉ざすものではない。

Allowing dynamic_cast, polymorphic typeid in Constant Expressions

dynamic_castとtypeidをコンパイル時定数にする変更。すでにコンパイル時にvirtual関数を使えるようになっているため、制限する理由がなくなった。C++20ではC++コンパイラーはコンパイル時に確保されたオブジェクトの型を把握して適切にディスパッチする必要がある。

p1006r1.pdf

std::pointer_traitsをconstexprに対応させる変更。std::vectorをconstexprにするために必要。

今回はまだ入らなかったが、動的メモリ確保も次回あたりにコンパイル時定数になる予定だ。つまりコンパイル時に動的メモリ確保ができるようになる上、その他の例外やらvirtual関数やらunionやらといった処理もすべてコンパイル時定数になるので、std::stringやstd::vectorがそのままconstexprに対応することになる。C++20ではほとんどの処理がコンパイル時定数になる。これは静的リフレクションを入れるために必要な変更だ。

Misc constexpr bits

標準ライブラリのconstexprにできる部分を積極的にconstexprにしていく変更。

P0668R4: Revising the C++ memory model

C++のメモリーモデルの変更。一部のアーキテクチャのとても弱い保証に対応した。一部のアーキテクチャー、PowerやNVIDIAのGPUとARMは、memory_order_seq_cstに対応しつつrelease/aquireに対応できない。memory_order_seq_cstの存在を許すaquire/releaseを実装するためには、よりペナルティの高い強めのフェンスを挿入しなければならない。しかしそのような理論的な問題のためだけに強いフェンスを使いたくはない。そのために、memory_order_seq_cstには対応しない弱いatomic型を追加する。

P1236R0: Alternative Wording for P0907R4 Signed Integers are Two's Complement

符号付き整数型の値の表現は2の補数であることがC++の規格で保証する変更。

char8_t: A type for UTF-8 characters and strings (Revision 5)

UTF-8文字リテラル、UTF-8文字列リテラルの文字の型を表現するchar8_tを追加する提案。私が9年前にC++0xのときに提案したところ、「でもcharは生のバイト列を表現するのに適切な型だからー」と寝ぼけた主張で却下されたにもかかわらず、後になって「やっぱchar8_tにしとけばよかったなぁ」となったので変更された。私には愚痴を言う権利がある。

Nested Inline Namespaces

インライン名前空間をネストで書けるようにする。


namespace lib::container {
    inline namespace v1 {
        namespace node {
        }
    }
}


namespace lib::container {
    inline namespace v2 {
        namespace node {
        }
    }
}

のように中間のinline名前空間を書く際にはC++17に追加されたネストされた名前空間で書けなかったが、


namespace lib::container::inline v1::node {
}

namespace lib::container inline v2::node {
}

のように書けるようにする。

p1289r0.pdf

contractの中ではアクセス指定を無視する変更。

p1007r2.pdf

std::assume_aligned<N>(ptr)の追加。ポインターptrの指すアドレスがNでアラインされていることをコンパイラーにヒントとして与える


// intの配列から合計をSIMD演算で計算する関数
int sum_ints( int * ptr, std::size_t n )
{
    std::assume_aligned( ptr, alignof(int) ) ;    
    // アライメント要求のあるSIMD演算で合計を計算
    return 
}

実際に指定したアライメントになっていることを保証するのはユーザーの仕事だ。std::assume_alignedはアライメントが保証されていると仮定してよいとコンパイラーにヒントを与えることによって、コンパイラーがSIMD演算のようなコード生成を行うときに、アライメント調整用のコードを生成せずに住むようにする。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1085r2.md

spanからoperator ==を取り除く変更。spanをregularにするために必要な変更。

STLの作者Alexander StepanovはC++では型はRegularであるとが重要だと力説した。型がRegularでない場合、もたらす利便性よりも混乱のほうが大きくなる。

コピーコンストラクターとコピー代入演算子は、オブジェクトの「値」をコピーする。

operator ==やoperator <はオブジェクトの「値」を比較する。

型がRegularであるためには、コピーと比較は同じ「値」を比較しなければならない。コピーと比較で「値」の定義が異なっている場合、混乱の元だ。

さて、spanはどうなっているか。spanのコピーはshallowだ。つまり、ポインターとそのサイズがコピーされる。一方、spanのoperator ==はdeepだ。つまり、ポインターの参照する先のストレージが比較される。

spanをRegularにするためには、spanのoperator ==を廃止する。

Smart pointer creation with default initialization

make_unique_default_init<T>/make_shared_default_init<T>を追加する。これはデフォルト初期化されたunique_ptr<T>/shared_ptr<T>を返す。

size_t型の引数nを取るものもあり、こちらはunique_ptr<T[]>/shared_ptr<T[]>を返す。


// デフォルト初期化されたint型の値の
// std::unique_ptr<T>
auto p = std::make_unique_default_init<int>() ;
// それぞれデフォルト初期化されたint型の値で要素数が5の
// std::unique_ptr<T[]>
auto a = std::make_unique_default_init<int []>(5) ;

C++標準化委員会では、特定の分野について議論するStudy Groupが設置されるが、今回、新しいStudy Groupとして、SG19 Machine LearningとSG20 Educationが追加された。SG19は名前だけみると機械学習についてで、SG20は前から作ると宣言されていた教育に関するSGだ。

C++を発展させるEvolution Working Groupでは以下のような興味深い議論があった。

モジュールの中でmain関数を定義できる提案と、プログラムにデータを埋め込むstd::embed提案はより深い議論とフィードバックが必要だとされた。

void main提案は却下された。

興味深いのは、operator []の中の operator , の利用をdeprecatedにしようという決定だ。


int a[5] ;
a[1,2] ; // a[2]と同じ

このコードがdeprecated扱いになる。operator []の中のカンマは、多次元配列を実装するための何らかの新しい機能として予約される。

short float提案についてコンセンサスは得られなかった。

std::colonyはもっと作業が必要だとされた。

設計的には賛同できるのでC++20に追加する方向で進めるライブラリとして、テキストフォーマット(std::format)、スタックトレースライブラリがある。

SG13 Graphics Study Groupではオーディオに関する興味もあるらしい。またweb_viewに対するさらなる作業を推奨する雰囲気だ。

今後の予定としては、2019年春のKona会議でFeature freezeをし、2019年夏のドイツのCologne会議でCommittee Draftの文面を完成させる。つまり来年の半ばにはC++20の概要は決定するわけだ。

モジュールはおそらくC++23以降に延期される。コルーチンやExecutorも延期される。ネットワークライブラリはおそらくC++26以降になるだろう。