2017-10-30

C++標準化委員会の文書: P0260R2-P0356R2

P0260R2: C++ Concurrent Queues

名前通り、競合なく複数のスレッドからアクセスできるconcurrent queueの提案。ヘッダーファイルは<conqueue>、キュー本体の名前はbuffer_queue。

P0275R2: A Proposal to add Classes and Functions Required for Dynamic Library Load

C++にshared library(WindowsではDLLと呼ばれている)機能を追加する提案。

shared library機能は広く使われているが、現在C++規格はshared libraryを直接サポートしていない。


// libearth.soという名前のshared libraryファイルを読み込む
shared_library lib("libearth.so") ;
// シグネチャがint(std::string)でシンボル名がquestionの関数へのポインターをlibearth.soから得る
auto ptr = lib.get_if<int (std::string)>("question") ;

int result = ptr("the answer to life the universe and everything"s) ;

[PDF] P0303R0: Extensions to C++ for Short Float Type

floatより小さいshort floatの提案。

short float x = 1.0sf ;

規格はshort floatのサイズとフォーマットを規定していないが、背景にはIEEE 754-2008のhalf precision floating pointであるbinary16を念頭に置いている。

[PDF] P0315R3: Lambdas in unevaluated context

lambda式を未評価式の中でも使えるように制限緩和する提案。ただし、外部リンケージを持つ関数のシグネチャーにlambda式が含まれないように注意深く制限はする。

[PDF] P0323R3: Utility class to represent expected object

expected<T,E>の提案。このクラステンプレートはT型の値を保持することが期待されているが、T型の値を保持できないときには、期待通りではないエラーの意味を示すためにE型の値を保持する。

ある型の値を用意できないときに、値を保持していないことを示すためには、optional<T>が使えるが、エラーの詳細な情報を伝えたいときには、エラー通知用の型の値を渡したい。そのために、ここで提案しているある型かエラー型の値を保持するexpectedが使える。

[PDF] P0327R3:Product types access

構造化束縛で分解できる型をすべて分解することができる機能の提案。ようするにジェネリックなtuple_size/tuple_element/getの提案だ。

コア言語でやる場合、size/element/getの機能を提供する演算子を提供することになるが、キーワードの追加が必要になる。そしてtraitsでカスタマイゼーションポイントを提供しているライブラリでは使えない。

ライブラリでやる場合、現状のコア言語仕様ではビットフィールドに対応できない。

これは必要だ。

[PDF] P0330R1:User-Defined Literals for size_t

std::size_tに対するユーザー定義リテラル。zu。

#include <cstddef>
using namespace std::support_literals ;

// std::size_t
auto x = 0zu ;

これはほしい。std::support_literalsではなく、すべての標準ライブラリのユーザー定義リテラルを使えるようになるstd::literalsでもよい。

P0332R1: P0332r1 : Relaxed Incomplete Multidimensional Array Type Declaration

mdspan(多次元配列スパン)のために不完全配列の宣言の文法の制限を緩和する提案。添字数を一切書かなくてよくなるので、int[][][]などと書けるようになる。

これにより、以下のようにmdspanが書けるようになる。

// 現在提案中のmdspanの宣言
// 3次元テンソル型
using tensor = std::mdspan<double,std::extents<std::dynamic_extent,std::dynamic_extent,std::dynamic_extent>> ;

// この提案が入れば書けるようになる上と同等の宣言
using tensor = std::mdspan<double[][][]> ;

楽になる。

しかし、連続したストレージを所有しない多次元配列に見せかけるラッパークラスとして、mdspanという名前は本当に通じるのだろうか。これはもともとarray_viewと呼ばれていたが、viewという用語は正しくないと物言いがついたために、spanになった。mdspanとは、Multi-Dimentional spanだ。果たして日本語でスパンといって伝わるのだろうか。

ただ、考えてみれば、ラッパーとかサンクといった用語も当初は日本人に馴染みのない用語だったはずで、イテレーターやデリゲートやクロージャーといった用語も最初は聞き慣れない用語だったはずだ。かつてはアドレスを番地と言ったものだ。

P0355R4: Extending <chrono> to Calendars and Time Zones

chronoをカレンダーとタイムゾーンに対応させる提案。これでようやくC++で日付処理が可能になる。

P0356R2: Simplified partial function application

std::bindにかわる新しいbind_frontの提案。この提案ではstd::bindのdeprecated化を提案している。

引数を5個とる関数fが以下のようにあるとして、

int f( int, int, int, int, int ) ;

これの第一引数だけ指定して残りを受け取る引数4個の関数を作り出す場合、std::bindでは以下のように書く。

bind( &f, 42, _1, _2, _3. _4 ) ;

わりとだるい。そもそも実引数の数を把握してそのとおりに書くのがとてもだるい。

lambda式ならどうか。

[]( auto && ... args ) { return f( 42, std::forward<decltype(args)>(args)... ) ; } ;

割と難しい。このようにC++14のlambda式を使いこなし、かつPerfect Forwardingも完璧にスラスラと書けるようになる頃には、京都で9年ぐらいニートした挙句にC++の参考書を出版するようになっているか、岡山で陶芸でもしている。

bind_frontは先頭の引数だけを指定することに特化したライブラリだ。以下のように書ける。

bind_front( &f, 42 ) ;

まあ、わかりやすいとは思うが、そう都合よく先頭だけ引数を指定したい場合があるだろうか。

ドワンゴ広告

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

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

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

2 comments:

Anonymous said...

提案を見ると、bind_front の用途としては、this の bind が想定されている様子です。
たとえば、次のようなケースは決して少なくはないはずです:

class X
{
class Y;
bool is_less_than( const Y& lhs, const Y& rhs ) const;
void hoge()
{
std::vector<Y> vec;
std::sort( vec.begin(), vec.end(), /*ここでis_less_thanでソートしたい*/);
}
} ;

これを、わざわざ [this]( const Y& lhs, const Y& rhs) { return is_less_than( lhs, rhs ); } とは書きたくない。もっと簡単な文法が必要になります。
その解決法として、bind_this 的なものがあるのは極めて有用で、これを this に限らず第一引数に拡張したものが bind_front だと考えると、これは必須に近いものではないかと思われます。

……まあ、ベストは this->is_less_than とすると自動的に this が bind された is_less_than になる、みたいに文法側に手を入れる事なのですが。とはいえ、C++でこれは難しいでしょうから。

Genya MURAKAMI said...

私としては、記述を短縮する(もしくはVariadic arguments に対応させる)目的には、
std::bind の別なバージョンを用意するよりも、プレースホルダを拡張すべきであると思う。

Sprout の Variadic Placeholder は、bind(f, 42, _va) のような形で、提示された例を解決できる。
https://wandbox.org/permlink/rNhLgv2EVOxJQklb