2016-11-07

C++標準化委員会の文書: P0430R0-P0439R0

[PDF] P0430R0: File system library on non-POSIX-like operating systems

<filesystem>はPOSIX準拠のファイルシステムを前提にして設計されているが、POSIX以外のファイルシステムの対応も考慮している。その考慮が浅い部分がいくつかあるので修正案。

P0432R0: Implicit and Explicit Default Comparison Operators

暗黙と明示的な比較演算子を生成する提案。

前回の提案では、比較演算子をそれぞれクラスの定義内で=defaultするものであった。これは極めて冗長であり、プリプロセッサーマクロが書かれることが予想できる。

今回の提案は、operator ==とoperator <を=default、=deleteすると、残りは暗黙に生成してくれる。

  • 明示的に比較演算子を生成する=defaultの文法
  • deleted定義する=deleteの文法
  • 生成された比較演算子は条件次第でconstexprやnoexceptになる
  • aとbが同じ型の場合、a == bはEquality-by-subobjectする
  • aとbが同じ型の場合、a < b はLess-than-by-subobjectする。
  • a == b が定義されていてdeleted定義されていない場合、a != b は!(a==b)として生成される
  • a < b が定義されていてdeleted定義されておらず a > b がユーザー定義されていない場合、a > b は b < a として暗黙に生成される
  • a == bとa < bが定義されていてdeleted定義されておらずa <= bがユーザー定義されていない場合、a <= bはa == bもしくはa < bとして暗黙に生成される
  • a <= bが定義されていてdeleted定義されておらず a >= がユーザー定義されていない場合、a >= bはb <= aとして暗黙に生成される。

Equality-by-subobjectは、operator ==を使ってサブオブジェクト同士を比較するものだ。

Less-than-by-subobjectは、operator ==とoperator <を使ってサブオブジェクト同士を比較するものだ。

例えば、


struct A { } ;

に対しては、以下のような比較演算子が生成される。

constexpr bool operator==(A const &, A const &) noexcept {
    return true;
}
constexpr bool operator!=(A const &, A const &) noexcept {
    return false;
}

以下のコードは、コンパイルエラーになる。

struct B {
    A a;
};
bool operator<(B const &, B const &) = default;

理由は、クラスAはoperator <を提供していないからだ。

以下のように書くと、

struct C {
};
bool operator<(C const &, C const &) = default;

以下のような比較演算子が暗黙に生成される。

constexpr bool operator==(C const &, C const &) noexcept {
    return true;
}
constexpr bool operator!=(C const &, C const &) noexcept {
    return false;
}
constexpr bool operator<(C const &, C const &) noexcept {
    return false;
}
constexpr bool operator>(C const &, C const &) noexcept {
    return false;
}
constexpr bool operator<=(C const &, C const &) noexcept {
    return true;
}
constexpr bool operator>=(C const &, C const &) noexcept {
    return true;
}

以下のように書くと、

struct E {
    int a;
    int b;
    std::string c;
    bool operator<(E const &) const = default;
    bool operator<=(E const &) const = delete;
};

以下のような比較演算子が暗黙に生成される。

inline bool operator==(E const & lhs, E const & rhs) {
    return lhs.a == rhs.a and lhs.b == rhs.b and lhs.c == rhs.c;
}
inline bool operator!=(E const & lhs, E const & rhs) {
    return !(lhs == rhs);
}
bool E::operator<(E const & other) const {
    if (this->a == other.a) {
        return false;
    }
    if (this->a < other.a) {
        return true;
    }
    if (this->b == other.b) {
        return false;
    }
    if (this->b < other.b) {
        return true;
    }
    return this->c < other.c;
}
inline bool operator>(E const & lhs, E const & rhs) {
    return rhs < lhs;
}
bool operator<=(E const &, E const &) = delete;

だいぶマシな提案になった。

P0433R0: Toward a resolution of US7 and US14: Integrating template deduction for class templates into the standard library

C++17にはクラステンプレートのコンストラクターに実引数推定が追加された。これにより以下のように書ける。

template < typename T >
struct A { } ;

// A<int>
A a(1) ;

この機能を追加することにより、既存の標準ライブラリにどのような影響を与え、どのような対応が必要か調査が必要だというNBコメントに応える形で、標準ライブラリすべてを調査した結果、多くのライブラリでdeduction guideが必要であることが判明した。

コンストラクターはテンプレート仮引数名以外の型を使うこともあるので、実引数推定ができないことがある。例えばvectorにはイテレーターのペアを取るコンストラクターがある。


template < typename T, typename Allocator = std::allocator >
class vector
{
public :
    template < typename Iter >
    vector( Iter begin, Iter end ) ;
} ;

このような場合に、deduction guideという文法を使って、型推定のヒントを与えることができる。

template < typename Iter >
vector( Iter, Iter )
    -> vector< iterator_traits<Iter>::value_type > ;

この文書は、標準ライブラリでdeduction guideが必要な場所を列挙している。

[PDF] P0434R0: Portable Interrupt Library

ポータブルな割り込み処理のためのライブラリの提案。

割り込み処理はデバイスドライバーやファームウェアの実装に重要な処理であるが、C++は標準の割り込み処理方法を提供していない。そのため、てんでばらばらな方法で実装されている。そこで、標準の割り込み処理用のライブラリを提供することで、割り込み処理をポータブルに書けるようになる。

device_baseはTriggerというpure virtual関数を持っていて、派生して実装する。割り込み番号やタイマー割り込みを処理できと、大雑把なことが書いてある。

趣旨はわかるが、デバイスドライバーやファームウェアのプログラマーは出力されるアセンブリ言語がわかるほどの低級なコードを好むという偏見があるのだが、果たして標準の割り込みライブラリなど可能なのだろうか。

[PDF] P0435R0: Resolving LWG Issues re common_type

common_typeに持ち上がっている様々な問題を解決すべく、コンセプトを用いたcommon_typeの実装の提案。

問題はコンセプトが入らないことだが。

[PDF] P0436R0: An Extensible Approach to Obtaining Selected Operators

比較演算子の自動生成の提案。

比較演算子を自動的に生成するP0221が却下されてしまったので、別の提案が出てきている。この提案では、P0221の問題のない部分だけを入れる提案だ。

常識で考えて、a == bとa != bの結果は異なるものであるべきだ。また、boolを返すoperator <が比較の意味で定義されている場合、その他の演算子も、x > yがy < x、x >= yが!(x < y)、x <= yが!(y < x)と考えるのが最も自然だ。

ならば、この自動的な解釈だけ提案しよう。つまり、a != bと書いて、boolをoperator ==が定義されていて、operator !=が定義されていない時、a != bは!(a == b)と解釈される。その他も比較演算子も同様。

この提案では、比較の大本であるoperator ==とoperator <を自動的に生成することはないが、このふたつの比較を使って他の比較を自動的に生成する。

[PDF] P0437R0: Numeric Traits for the Next Standard Library

<limits>, <cfloat>, <cmath>に点在する数値の特性を取得するメタ関数を、モダンなtraitsベースの設計のライブラリ、<num_traits>に集約する提案。

例えば、numeric_limits<T>::max()と書いていたものを、num_max<T>::valueもしくはnum_max_v<T>もしくはnum_max<T>{}と書ける。

便利なので追加されてほしい。

[PDF] P0438R0: Simplifying simple uses of <random>

に持ち上がっている数々の提案を寄せ集めたTSを作ろうと言う提案。これ自体には特に内容はない。

P0439R0: Make std::memory_order a scoped enumeration

タイトル通りmemory_orderをscoped enumにする提案。

今のmemory_orderは、C言語風のクソみたいな流儀で定義されている。これは、もともとatomicをCとC++で共通化する目的だったが、C言語はC言語で_Atomicのようなこれまたクソみたいな文法を追加したので、C++としてもmemory_orderをC言語のクソみたいな流儀に合わせる理由は、もはや何もなくなった。

そこで、scoped enumを使う。

現在のクソみたいなmemory_orderの定義

 namespace std {
    typedef enum memory_order {
      memory_order_relaxed, memory_order_consume, memory_order_acquire,
      memory_order_release, memory_order_acq_rel, memory_order_seq_cst
    } memory_order;
  }

これを以下のようにする。

  enum class memory_order {
      relaxed, consume, acquire, release, acq_rel, seq_cst
    };

互換性のために、以下の定義も追加する。


    inline constexpr auto memory_order_relaxed = memory_order::relaxed;
    inline constexpr auto memory_order_consume = memory_order::consume;
    inline constexpr auto memory_order_acquire = memory_order::acquire;
    inline constexpr auto memory_order_release = memory_order::release;
    inline constexpr auto memory_order_acq_rel = memory_order::acq_rel;
    inline constexpr auto memory_order_seq_cst = memory_order::seq_cst;

これは即座に追加されるべきだ。C言語のクソな流儀を取り払え。

ドワンゴ広告

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

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

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

2 comments:

Anonymous said...

ファイルシステムは無事一般化されそうですかね。これも結構大変だろうと思いましたが何とかなりそうですね。もしかして個人的には不可能だと思ってるGUIシステムさえも!?
比較演算子関係はDにあるやつに近くなってきましたね。自動定義は楽なのでやってほしいです。
テンプレート類推はよくできたなぁというのが一感です。
デバドラ関係ももしかしたら叡智でできるのでしょうか??まぁ、アセンブリを結局いじるというのは同感なので難しそうです。
コモンタイプは駄目ですね。static_castできないじゃないですか。2変数取るならわかるんですが、1変数間の変換が大変なのは受け入れがたいです。
num_max系はまぁいいですけど、関数チェインがあればスッキリするのになーと思いました。リフレクションが入って型に対する関数チェインができるようになったらもっとスッキリしますよ。C#からの発想ですが。

Anonymous said...

a!=b と !(a==b) が等しいのは常識で考えれば当たり前でも、その常識が通用しないのが現行の C++ ですので。
浮動小数点なんかは NaN が絡むとあっけなくこの常識が崩壊しますし、 PDF に出てくる std::complex はこの影響を強く受けているはずなのですが、 PDF では触れられていませんね。