2013-07-03

2013-07 mailingの簡易レビュー

2013-07 mailingが公開された。

CD(Committee Draft)はN3690、Working DraftはN3691だ。

C++14としては、もうCDがこれ以上大幅に変更されることはないだろう。

また、今回の論文は、C++14のCDを変更するものではなく、C++14以降の将来の変更の方向性を示すものであると書かれている。

N3692: C++ Editor's Report, May 2013

C++ドラフトの編集者による、今回の変更部分の報告。今回はかなり詳細にまとめられている。

N3693: Draft Filesystem Technical Specification

Filesystemライブラリの文面案。

よくぞここまできっちり書き上げたなぁと思うぐらい、詳細に書かれている。世の中の仕様書もこれぐらい詳細に書かれていたら、世のプログラマーの仕事は相当に楽になるであろうに。

N3694: Feature-testing recommendations for C++

Cプリプロセッサーを使って機能テストをする際に役立つ、実装によって定義済みのマクロの推奨。

C++11実装のコンパイラーやライブラリが発展段階の現状、ある機能が実装によってサポートされているかどうかを調べるために、例えば以下のようなクソ汚いクソプリプロセッサーが書かれている。

#ifndef __USE_RVALUE_REFERENCES
  #if (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 3) || \
      _MSC_VER >= 1600
    #if __EDG_VERSION__ > 0
      #define __USE_RVALUE_REFERENCES (__EDG_VERSION__ >= 410)
    #else
      #define __USE_RVALUE_REFERENCES 1
    #endif
  #elif __clang__
    #define __USE_RVALUE_REFERENCES __has_feature(cxx_rvalue_references)
  #else
    #define __USE_RVALUE_REFERENCES 0
  #endif
#endif

このコードの目的は、rvalue referenceがサポートされているかどうかによって、__USE_RVALUE_REFERENCESマクロ定義を0か1にすることである。このマクロは、コードの別の場所で、実装をコンパイル時に切り替えたりするのに使える。

このようなクソコードはクソ書きたくない。第一、新しいC++実装をサポートするたびに書きなおしだ。どうせこのようなコードが必要悪なのだとすれば、ある機能をサポートしているかどうかの定義済みマクロを、実装が提供しているべきではないのか。あるいは、実装が提供しておらず、ユーザーが定義しなければならないとしても、マクロの名前は推奨の業界標準があるべきではないのか。

というわけで、そのような定義済みマクロの名前と値の推奨を行う論文。これは実装への強制ではなく、単なる推奨となる。

たとえば、実装が二進数リテラルをサポートしている場合、__cpp_binary_literalsが定義される。

マクロの値は、該当機能の論文が投票でworking draft入りに可決された年と月を示す。たとえば、二進数リテラルのマクロ__cpp_binary_literalsの値は、2013年4月にドラフト入りが可決されたので、201304となる。

これにより、例えば後のドラフトで機能変更が起こった場合でも、マクロの値を見ることによって、いつ可決されたときの仕様なのかが分かる。

また、この論文では、現行のC++14 CDには入っていない、ある名前のinclude fileが存在するかどうかを調べる__has_includeが、C++14に採用されることを前提にしている。

私は、クソプリプロセッサーは一刻も早く廃止すべきだという立場なので、クソプリプロセッサーを使うあらゆるクソ機能に断固としてクソ反対する。

[立場上でなくても当然クソ反対するクソPDF] N3695: SG5: Transactional Memory (TM) Meeting Minutes 2013/03/11-2013/06/10

Transactional Memoryの会議の議事録。

N3696: Proposal to extend atomic with priority update functions

atomic操作で一般的な操作として、値を読み込み、何らかのpredicateで比較し、predicateがtrueを返す時に、値を更新するという操作がある。この操作で、predicateとしてよく用いられるのは、less thanやgreater thanである。このような操作は、任意のpredicateに対して汎用的に実装できるので、ライブラリとして提供する提案。また、よく使われるless thanやgreater thanに対しても、それぞれfetch_minとfetch_maxという名前で提供する。

実装は以下のようになる。

template <typename V>
T priority_update(T value, V predicate)
{
  T read = this->load();
  while (predicate(value, read) {
    if (this->compare_exchange_weak(read, value))
      return read;
  }
  return read;
}

T fetch_min(T value)
{ return priority_update(value, less<T>); }

T fetch_max(T value)
{ return priority_update(value, greater<T>); }

これは、atomicクラスのメンバー関数として実装し、さらに外部の関数テンプレートとして、atomic_priority_update, atomic_fetch_min, atomic_fetch_maxも提供する

N3699: A proposal to add a generalized callable negator

汎用的なnegatorであるnot_fnを追加する提案。従来のnot1やnot2は、引数の数がひとつかふたつに限られている。Boostでfunctionやbindの実装が研究され、またVariadic Templatesがある今、もっと汎用的なnegatorを提供できる。

N3700: Hierarchical Data Structures and Related Concepts for the C++ Standard Library

汎用的なツリー構造を、STLのコンテナーのようなインターフェースのライブラリとして提供する提案。利用者がツリー構造の実装の詳細に関わらずに、ツリー構造を使えるようになる。

元々は、Google Summer of Code 2006でBoostに含めるべく実装が試みられたもので、いまだに実装は完成していないのだが、ソースコードはGitHubで公開されている。

grafikrobot/boost-tree · GitHub

setやmapといった特別な用途の実質バイナリツリーではなく、もっと汎用的に使えるツリー構造のライブラリというのは面白い。ただし、既存の実装例がなく実装中で、まだBoostに正式に取り込まれておらず、実装例の利用例も乏しい現状では、もうすこし成熟するのを待ったほうが良さそうだ。実際に利用してみないとインターフェースの良し悪しは分からない。

[まるで暗い未来を暗示するかのようなPDF] N3701: Concepts Lite

もうすでに紹介したが、Concept Liteの論文。[PDF注意] N3580の改訂版。

[title要素のない失礼なHTML] N3702: Introducing an optional parameter for mem_fn, which allows to bind an object to its member function

mem_fnに仮引数を追加してクラスオブジェクトを割り当てられるようにする提案。

例えば以下のような関数があったとする。

double integrate(
    std::function<double(double, double, double, double, double)> f,
    double x1, double x2, double y1, double y2, double z1, double z2,  double a1, double a2, double b1, double b2
) ;

fに渡される実引数は、残りの実引数から計算される。

この関数の最初の実引数に以下のようなクラスのメンバー関数A::faを関数オブジェクトとして渡したい場合、

class A
{
     double p;
 
public:
     A(double p1):p(p1) {}
     void set_param(double p1) {  p = p1; }
     double fa(double x, double y, double z, double a, double b);
};

なんとかして、A::faの呼び出しには、クラスAのオブジェクトを結び付けなければならない。

それにはいろいろ方法がある。

1. bindを使う方法

double r =  integrate( std::bind(&A::fa, &a, _1, _2, _3, _4, _5),
    x1, x2, y1,y2, z1, z2, a1, a2, b1, b2);

わざわざ_1から_5まで指定しないといけないのが強烈に面倒だ。

lambda式を使う方法

double r = integrate(
    [&a](double x, double y, double z, double a, double b) { return a.fa(x, y, z, a, b);},     
    x1, x2, y1, y2, z1, z2, a1, a2, b1, b2); 

わざわざ仮引数、と実引数をforwardするのが強烈に面倒だ。

グローバル関数でラップする方法

// 何らかの方法でクラスAのオブジェクトを取得
double f(double x, double y, double z, double a, double b) { return a.fa(x,y,z,a,b); }

double r = integrate(f, x1, x2, y1, y2, z1, z2, a1, a2, b1, b2);

汚い。

この問題は、単にメンバー関数にクラスオブジェクトを束縛できるライブラリがあれば、とても簡潔に書ける。

double r = integrate(some_binder(&A::fa, &a), x1, x2, y1, y2, z1, z2, a1, a2, b1, b2); 

そこで、mem_fnにそのような機能を追加しようという提案。

[titleのない失礼なHTML]N3703: Extending std::search to use Additional Searching Algorithms (Version 3)

N3606の改訂版。既存std::searchを拡張し、BMなどの検索アルゴリズムを引数で指定できるようにする提案。

No comments: