本の虫

著者:江添亮
ブログ: http://cpplover.blogspot.jp/
メール: boostcpp@gmail.com
Twitter: https://twitter.com/EzoeRyou
GitHub: https://github.com/EzoeRyou

アマゾンの江添のほしい物リストを著者に送るとブログ記事のネタになる

筆者にブログのネタになる品物を直接送りたい場合、住所をメールで質問してください。

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すると、残りは暗黙に生成してくれる。

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