2015-10-07

C++標準化委員会の文書2015-09 pre-Konaのレビュー: P0001R0-P0009R0

今回から、文書番号の規則が変わっている。PxxxxRxというフォーマットになっている。Pxxxxが文書番号で、Rxがリビジョン番号だろう。たしかに、今までどの文章がどの文章の改訂版かわかりにくかったので、いい変更だ。

P0001R0: Remove Deprecated Use of the register Keyword

registerキーワードを廃止する提案。registerキーワードは2011年にdeprecatedになり、将来のために予約されることになった。C++17では廃止する。

廃止するにあたっての懸念は、Cとの互換性だ。例えば、関数のシグネチャがCとC++で変わってしまう。とはいえ、registerキーワードの使用はCでも廃れているし、もっと利用例があるrestrictキーワードでさえ、この15年の間、CとC++との互換性にそれほど大きな問題を引き起こしていないので、大丈夫とのこと。

register機能は廃止されるが、registerキーワードは、将来の利用のために予約される。一般的な英単語のキーワードは極めて貴重である。

registerを予約語から消してユーザーに識別子として解放する案は、会議により否決された。

キーワードといえば、asmも実質廃止しても良さそうな気がする。というのも、C++規格のasmの文法は極めて使いづらいので、現実のコンパイラーは__asmなどの独自のキーワードを使ってインラインアセンブリを提供している。

NP0002R0: Remove Deprecated operator++(bool)

boolに対するoperator ++を廃止する提案。以下のようなコードが違法になる。

bool b = true ;

++b ; // false
++b ; // true

boolに対するoperator ++は、そもそも正式な規格以前の機能で、C++98ですらdeprecated扱いになっている。もう20年以上の猶予期間を与えてやったのだから、いい加減にいいだろうということだ。

なお、後置演算子はまだ利用価値がある。というのも、現在の値を得つつ値を変更できるからだ。

void f( bool b )
{
    g( b++ ) ; // 値を渡しつつ変更
}

この代替機能として、ライブラリにstd::exchangeが導入された。

void f( bool b )
{
    g( std::exchange( b, !b ) ) ;
}

P0003R0: Removing Deprecated Exception Specifications from C++17

動的例外指定を廃止する提案。

まともに利用されなかったので、すでにC++11でdeprecated扱いされている。

throw()だけは残されるが、noexcept(true)と同じ意味になる。

P0005R0: Adopt 'not_fn' from Library Fundamentals 2 for C++17

Library Fundamentals TSにあるnot_fnを標準ライブラリに追加する提案。

auto f = []( bool b ){ return b ; } ;
auto nf = not_fn(f) ;

f( true ) ; // true
nf( true ) ; // false

not_fnは小さいし、not_fnが依存する他のライブラリもないので、not1, not2の代替機能として。

P0006R0: Adopt Type Traits Variable Templates from Library Fundamentals TS for C++17

Library Fundamentalsにある変数テンプレートを使ったtype traitsのラッパーを標準ライブラリに追加する。traits::valueのかわりに、traits_vで値が返。is_same<T, U>::valueと書くかわりに、is_same_v<T, U>と書ける。

変数テンプレートは以下のように使う。

template < typename T, typename U >
constexpr bool is_same_v = std::is_same< T, U>::value ;

P0007R0: Constant View: A proposal for a 'std::as_const' helper function template

constなlvalueリファレンスを返す関すテンプレート、as_constを追加する。

利用例は以下の通り。

struct X {  } ;

void f( X & ) ; 
void f( X const & ) ;

int main()
{
    X x ;

    // 非const版
    f( x ) ; 

    // const版
    f( std::as_const(x) ) ;
}

関数を呼ぶときに、意図的に非constなオブジェクトから、const版のオーバーロードを呼び出したいときに使える。

わざわざconst_cast< const T & >( object )と書くのはだるい。しかもobjectの型Tを明示的に書かなければならない。const_cast< std::add_const< decltype( object ) >::type & >( object )と書けば明示的に型を書く必要はないが、極めてダルい。

実装例

template <class T> add_const_t<T>& as_const(T& t) noexcept
{
    return t ;
}

P0008R0: C++ Executors

スレッド風の実行媒体であるexecutorの提案。asyncをかなり高機能にしたものとも言える。スレッドプールなexecutorなどが提供される。

N4414で提案されていたtype erasure executorは懸念事項があるため見送り。

executorがシャットダウンするタイミングについては、main関数の実行を抜けたら自動的にシャットダウン。明示的にシャットダウンさせる方法については、まだ検討中。その他様々な会議での議論内容が書かれている。

P0009r00 : Polymorphic Multidimensional Array View

連続したストレージを多次元配列に見せかけるラッパー、array_viewが提案されているが、この論文は、array_viewはゼロオーバーヘッドの原則を満たさないし、異なるメモリレイアウトに対するゼロオーバーヘッドabstractionもできない欠陥品だとしている。この論文は、array_viewに対抗したviewライブラリを提案している。extentやstrideをconstexprで提供することによりコンパイラーの最適化の余地を高め、様々なハードウェアが直接サポートするレイアウトに直接マッピングできるようにするなどの設計になっている。とてもシンプルなので、viewというシンプルな名前こそがふさわしいと主張してる。

array_viewでfloat型の三次元配列[5][5][5]を宣言するには以下のようになる。

std::size_t size = 5 * 5 * 5 ;
float buffer[ size ] ;
array_view< float, 3>( size, buffer ) ;

対して、viewでは以下のように宣言する。

std::size_t size = 5 * 5 * 5 ;
float buffer[ size ] ;
view< float[5][5][5]> a( buffer ) ;

要素数がわからない場合は、以下のように設定する。

int x = 5, y = 5, z = 5 ;
float buffer[ x * y * z ] ;
view< float[][][] > a( buffer, x, y, z ) ;

コンパイル時にサイズがわかる箇所だけ書ける。

view< float [][5][] > a( ... ) ;

このような記法を可能にするため、コア言語にも手を入れる。配列の宣言子で、任意の添字の省略を認める。Clangではコードを一行修正するだけで対応可能だそうだ。

すごく大胆な提案だ。使い勝手は確かによい。

ドワンゴ広告

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

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

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

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

6 comments:

Anonymous said...

> ++b ; // false
えっ!
boolに対するoperator++がfalseになるような規格は存在していないはずだが?
boolに対してoperator++を適用した結果は常にtrueだよ

江添亮 said...

あ、本当だ。全く使わないので勘違いしていた。

Anonymous said...

ISOの方針がかわったと前コメント欄で読んだのですが無事公開されて何よりです。
ソースがここしかないのでぜひ江添さんには頑張っていただきたく思います。非常に無責任でごめんなさい。
VCのC++11でスレッドプール書いたらJoinしないとターミネートしちゃう仕様が邪魔で使い物になりませんでした。
スレッドの投げ捨てをしたかったのですがなんかいい方法あるのでしょうか。次期仕様に期待です。
たしか、現在ブロックするか取れるようになるんですよね?
VCが超絶バージョンアップしてほしいです。
array_viewはアウトオブレンジ例外投げてくれるんでしょうか?ベクターなんかで結構重宝しているので投げてほしいです。

Anonymous said...

割とどうでもいい話なのですが、ラムダから関数にポインタを生成できるようになりましたが、
コピーキャプチャのラムダはなぜポインタに変換できないのですか?
と、いうのもウインドウズを触っていて、クラスからWndprocを生成するときに、thisをキャプチャしたいのです。
参照キャプチャは短命なグローバル変数のようなものでちょっと問題あるとおもうのですが、
コピーキャプチャを制限した明示的な理由ってあるのでしょうか。
引数が外部的に増えただけに考えています。
ぜひ規制緩和をお願いしたいです。

Anonymous said...

つまりそれは、

std::string s;
auto f = [s]()->void{};

みたいなコードがあった時に、f を void(*)(const std::string&) に変換したいという事ですか?
WndProc の話が出てくるという事は、キャプチャーの情報を捨てた void(*)() に変換しなければいけないのではないでしょうか?

# 折角 SetWindowLongPtr があるんだからそれ使え。

Anonymous said...

ごもっとも。Orz