2014-04-09

2014-02 post Issaquah mailingsのレビュー: N3950-N3966

Post Issaquah論文集のレビューも、これが最後。長かった。

N3950: Defaulted comparison operators

かつて、Alexander Stepanovは、regular typeを提唱した。regular型は、自動的にコピー、代入、比較できるべきであると。

さて、C++では、コピーと代入は自動的にできるが、比較だけは自動的に出来ない。


class X
{
    int a ;
    int b ;
    int c ;
    int d ;
} ;

X a, b ;
a == b ; // ill-formed. 呼び出し可能なoperator ==は宣言されていない。
a < b ; // ill-formed. 呼び出し可能なoperator <は宣言されていない

さて、このクラスXの比較を実装してみよう。


bool operator == ( X const & l, X const & r )
{
    return 
        l.a == r.a &&
        l.b == r.b &&
        l.c == r.c &&
        l.d == r.d ;
}

bool operator < ( X const & l, X const & r )
{
    return
        l.a < r.a && l.a != r.a &&
        l.b < r.b && l.b != r.b &&
        l.c < r.c && l.c != r.c &&
        l.d < r.d && l.d != r.d ;
}

なんと言う機械的なコードだ。このようなコードは、人間が書くべきコードではない。特に比較演算子はひどい。

このような、基本クラスや非staticデータメンバーごとに比較は、自動生成できる。したがって、この論文は、C++に、デフォルトの比較演算子の定義を提案している。

過去のコードの挙動を変えないために、デフォルトの定義を使うには、明示的なdefault化を行わなければならない。


struct Thing {
    int a, b, c;
    std::string d;

    bool operator==(const Thing &) const = default;
    bool operator<(const Thing &) const = default;

    bool operator!=(const Thing &) const = default; 

    bool operator>=(const Thing &) const = default; 
    bool operator>(const Thing &) const = default; 
    bool operator<=(const Thing &) const = default;
};

すなわち、この提案されている機能は、opt-inである。opt-inであるために、既存のコードに影響を及ぼすことはない。

比較の順序は、基本クラスが書かれている順番に比較され、非staticデータメンバーが、宣言されている順番に比較される。


struct D : A, B, C
{
    int a ;
    int b ;
    int c ;
} ;

この例では、比較の順番は、A, B, C, a, b, cである。

[理解に苦しむPDF] N3951: C++ type reflection via variadic template expansion

これはどこまで本気なのか理解に苦しむ提案論文。

この論文で提案されている機能は、コンパイル時リフレクションだ。Variadic Templatesのパック展開を流用して、パック展開できる部分に、型のメンバーを展開できる機能を追加する提案となっている。

この提案は、パック展開を流用している。追加する文法は二つ。

  1. typename<T>...は、T型の名前と、T型のメンバーの識別子に展開される。0個目の展開結果にT型の名前、n個目の展開にn個目のメンバーの識別子の文字列が、UTF-8エンコードされたconst char *で展開される。
  2. typedef<T> ...は、T型のポインターと、T型のメンバーへのポインターに展開される。0個目の展開結果にTへのポインター型のnullポインター、n個目の展開にn個目のメンバーへのポインターが値として展開される。ただし、constexprメンバーは、値として展開される。
// 例
namespace ns
{

struct X
{
    int x ;
    int y ;
} ;

}

// { "ns::X", "x", "y"}と展開される
std::vector<std::string> identifiers{ typename<ns::X>... } ;

// { static_cast< ns::X * >(nullptr), &ns::x, &ns::y }と展開される
auto values = std::make_tuple( typedef<ns::X>... ) ;

新しいキーワードを必要としないし、ASTを弄くる必要もない。極めて質素な機能となっている。

利用例としては、Serializationやdelegatesやgetter/setterの生成、その他が挙げられている。

この論文では提案していないが、この機能を土台にしたサポート用のtratis(is_virtual_baseとかis_protected)などがあればよいと言及している。

また、メンバーを全部列挙するのはパフォーマンス的にも厄介なので、たとえばコンパイル時のフィルターがあれば良いともしている。つまり、typename < T requires U>という形で、Uというboolを返すconstexpr関数で、型に対するフィルターができるようにするなどという機能も議論されている。

また、文字列のエンコードはUTF-8だと明言しているのも興味深いところだ。

当初の提案では、基本クラスやネストされたクラスとその中身や、クラス定義の中のtypedefやenumとその中身まで含めたあらゆる情報を列挙しようというものだったらしいが、それはカオスになるとのことで、いまのレベルに抑えられたらしい。

N3883の壮大な提案と比べると、だいぶ現実的で最小限の質素な提案だ。ただ、これを扱うには、やたらと面倒なテンプレートメタプログラミングの技法が必要になるため、あまり

それにしても、typedef<T>...は、その質素な見た目とは裏腹に、強力すぎて難しい気がする。

ただ、筆者にとっては、N3883を見たときのような心躍るほどの衝撃はない。あれば便利な機能という程度の印象だ。

N3952: C++ Standard Core Language Active Issues

コア言語によせられて、現在議論されている問題集

N3953: C++ Standard Core Language Defect Reports and Accepted Issues

active issuesの中で、議論の結果、実際に問題であると判明した問題集と、その対応の一覧集。

N3954: C++ Standard Core Language Closed Issues

一度はactive issuesに載ったものの、議論の結果、実は問題ではなかったと判断され、取下げられた問題集の墓場。

[PDF邪魔すぎる] N3955: Group Member Specifiers

グループメンバー指定子(Group member Specifiers)の提案。

virtualとかstaticなどのメンバー指定子(member specifiers)は、しばしば連続して複数のメンバーに指定子なければならない。例えば、以下のようなコードになる。

// 冗長なコード
class foo : public bar
{
public:
    explicit foo(int);
    explicit foo(float);
    explicit foo(double);

protected:
    virtual T f() const override ;
    virtual U g() const override ;
    virtual V h() const override ;
    virtual W i() const override ;

private :
    static constexpr int X = 123 ;
    static constexpr float Y = 42.0f ;
    static constexpr double Z = 123.0 ;
} ;

ここでいう、explicitとかvirtualなどは、極めて冗長である。これをひとつにまとめられないか。

N3955提案では、アクセス指定子にメンバー指定子を記述する文法を新たに追加することで、メンバー指定子をグループ化することができる。

// N3955提案
class foo : public bar
{
public explicit :
    foo(int) ;
    foo(float) ;
    foo(double) ;

protected virtual const override :
    T f() ;
    U g() ;
    V h() ;
    W i() ;

private static constexpr :
    int X = 123 ;
    float Y = 42.0f ;
    double Z = 123.0 ;
} ;

これはどうだろうか。筆者には、机上の空論のように見える。教科書に載せるような短いサンプルコードはともかく、現実のコード(コメントやCプリプロセッサーなども含む)は、よりわかりにくくなってしまうような気がするのだが。

どうやら、文法上、指定子なら何でも指定できるようで、以下のようなコードさえ通ってしまう。

// N3955提案
struct X
{
public typedef :
    int int_type ;
    float float_type ;
    double double_type ;
} ;

文法上、以下のコードも通るはずだ。


struct X
{
public int :
    x = 0 ;
    y = 0 ;
    z = 0 ;
} ;

たしかに、冗長性は改善されるものの、うっかり間違いを増やすような気がするのだが。

[とても見づらいPDF] N3956: ISO/IEC CD 14882, C++ 2014 Responses to National Body Comments

NBコメントへの返答。特に目新しい回答はないようだ。

N3957: C++ Standard Evolution Active Issues List

Evolution、つまり、C++に提案されている新機能の文面案に対して議論されている問題集

N3958: C++ Standard Evolution Completed Issues List

上記の問題集にかつて載っていた問題で、対応が完了した問題集。

N3959: C++ Standard Evolution Closed Issues List

議論の結果、実は問題ではなかったとか、重複であったと判断された問題集。

[うんざりするほどPDF] N3960: Working Draft, Technical Specification for C++ Extensions for Parallelism

C++に並列実行を付け加えるTS(Technical Specification)のドラフト。<algorithm>に実行ポリシーを指定して、並列実行やベクトル実行を行える機能を定義している。

規格ではなくてTSなので、これを叩き台に、いずれはC++に取り入れられる合意が得られるような設計になる、かもしれない。

[不適切なtitle要素のHTML] N3961: A proposal to add shared_mutex (untimed)

N3891にあるように、現行のshared_mutexは、TimeLockable requirement(try_lock_for/try_lock_until)も満たすので、実は、shared_timed_mutexと命名されるべきである。そのように改名して、そして、TimeLockableではないuntimed shared mutexを、shared_mutexとして追加する提案。

TimeLockable要件を満たさないことにより、実装により効率的な実装をさせる余地を提供する。

つまりは、従来のshared_mutexを、shared_timed_mutex(try_lock_for/try_lock_untilをサポート)に改名した後釜に、新しいshared_mutex(try_lock_for/try_lock_untilをサポートしない)を提供する提案だ。

N3962: File System TS Editor's Report

Filesystem TSのドラフト編集者の報告書。前回の文面からの変更点が記載されている。

[中身もフォーマットも気に食わないPDF] N3963: Centralized Defensive-Programming Support for Narrow Contracts (Revision 4)

防衛的プログラミングを支援すると称するCプリプロセッサーマクロによるASSERTの変種の提案。

筆者はCプリプロセッサーマクロを使ういかなる提案にも反対の立場である。Cプリプロセッサーはいずれdeprecated扱いされなければならないのだ。

[二つ続けて悲惨なPDF] N3964: Library Foundations for Asynchronous Operations, Revision 1

N3896の改訂版。futureは力不足だ。コールバックこそが最もパフォーマンスがよいことを示し、その上で、futureモデルとコールバックモデルを両方サポートできる設計が必要だと主張している論文。

N3965: Proposal for Unbounded-Precision Integer Types

上限を定めない制度の整数型の提案。いわゆるBigIntの系譜だ。提案は、integerという演算子オーバーロードを駆使して、整数のように振る舞うクラスを提案している。

この手のライブラリは、何度も議論に上がるのだが、どうもなかなか議論が進まない。やはり、万人を満足させる多倍長整数演算ライブラリの設計は難しいのではないだろうか。

もちろん、そのようなC++用のライブラリは、すでに独立した実装が多数ある。しかし、任意の精度の整数演算ができる機能は、モダンなプログラミング言語には標準で備わっている機能なので、C++でも標準化されて欲しいところだ。

N3966: Fixes for optional objects

Issaquah会議で指摘された、optionalの文面上の問題を修正する提案。

今週が始まってから、まだ一度もドワンゴ社内でカタンをしていないので、ドワンゴ勤務中に論文レビューがはかどってしまった。なんということだ。

とりあえずたまっているC++論文の解説は片付いたので、今月末まで、付け焼刃的にECMA-262 Edition 5.1でも読もうかと思う。

ドワンゴ広告

この記事は、ドワンゴ社内でボードゲームをしていない暇に書かれた。

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

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

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

No comments: