C++14の仕様策定が完了しました

C++14のDIS(Draft International Standard)に対する各国の投票が行われ、満場一致で承認されました。各国から(主に日本から)のコメントによる文面の細かな修正が残っていますが、その作業が完了次第、ISO/IEC 14882:2014(E) Programming Language C++、別名C++14の規格が発行されます。

C++14は、2011年に発行されたC++11に対するマイナーバージョンアップです。小さな機能追加、および文面のバグ修正が含まれます。

C++14の更新内容は、以下のエントリにまとめてあります:

次はC++17です。そちらはメジャーバージョンアップになる予定で、その議論はすでに始まっています。

C++Now! 2014のセッション概要翻訳が完了しました

C++Now! 2014のセッション概要翻訳が完了しました。

C++Now!はBoostの開発者やC++標準化委員会のメンバが多く集まる、C++の最も濃いイベントです。そのセッション内容はどれも有用ですが、その資料全てを翻訳する余裕はありません。

それでもその有用な情報に触れるきっかけになればと思い、boostjpサイトでは、C++Now!のセッション概要を翻訳して公開しています。

この翻訳も、BoostCon時代から続いて5年目になります。これだけの量を毎年よく訳してるなーと自分でも思いつつ、今回も完成に向けてご協力していただいたzakさん、eagle_raptorさん、chichimotsuさんに感謝します。

Fisher-Yates Shuffle

てきとうに抜粋して書く。

以下のシャッフルアルゴリズムは間違っていて、

def incorrect_shuffle(items):
    for i in range(len(items)):
        randomIndex = random.randint(0, len(items)-1)
        temp = items[randomIndex]
        items[randomIndex] = items[i]
        items[i] = temp
    return items

これには、以下の3つの問題がある:

  1. 偏る
  2. 偏る
  3. 偏る

実は1つだったけど、これは大きな問題だ。

Fisher-Yates Shuffle (Knuth Shuffleとも呼ばれる)の実装は、以下のようになる:

def fisher_yates_shuffle(items):
    for i in range(len(items)):
        randomIndex = random.randint(i, len(items)-1)
        temp = items[randomIndex]
        items[randomIndex] = items[i]
        items[i] = temp
    return items

違いは、以下の1行。

従来のアルゴリズム

randomIndex = random.randint(0, len(items)-1)

Fisher-Yatesのアルゴリズム

randomIndex = random.randint(i, len(items)-1)

乱数範囲の開始が0iになっただけだけど、統計をとると偏りがなくなったことがわかる:

ちなみに、C++標準ライブラリに含まれるstd::shuffle()の実装を調べたところ、GCC 4.9 (libstdc++)、Clang 3.4 (libc++)、MSVC2013のいずれも、Fisher-Yatesを使っていた。([i, size)ではなく[0, i)のバージョン)

参照

変更履歴

  • 2014/08/12 15:14 MSVCは従来のアルゴリズムではなくFisher-Yatesを使っていたので、訂正
  • 2014/08/12 15:18 libstdc++とlibc++もFisher-Yatesだったので訂正

Boost.勉強会 #16 大阪

9月20日(土)に、大阪でBoost.勉強会を開催します。主催は遥佐保さんです。

ひさしぶりの大阪開催ですので、この機会にぜひご参加ください。

Boost 1.56.0がリリースされました

GitHubへの移行とモジュール化

このバージョンから、Boostの開発リポジトリSubversionからGitHubに移行しました。それにともない、GitHub上ではBoostの各ライブラリが、モジュールという単位で分割されるようになりました。モジュールは、関連するライブラリを集めたものや、Boostのいろいろなライブラリで使うベースライブラリをまとめたものです。CoreやWinApiなどのモジュールは後者になります。

新ライブラリ

Boost 1.56.0では、アラインメントを扱うAlignライブラリと、C++11のstd::type_indexのBoost版でもあり、それの拡張も入っているType Indexライブラリが追加されました。

非推奨ライブラリ

BoostからC++11標準に入れるたたき台となっていたライブラリ群であるTR1が非推奨になりました。このライブラリは、Boostの機能をstd::tr1名前空間で定義し直しただけのものなので、Boostの機能を使うか、C++11標準ライブラリを代わりに使ってください。

その他主要な更新

  • boost::variantが可変引数テンプレートに対応しました。コンパイルがいくらか速くなることを期待できます。
  • Containerに、DLmallocベースのアロケータが入りました。
  • Containerのmapsetの実装に使用するツリー構造が、選択できるようになりました。
  • Flyweightが、可変引数テンプレート、ムーブ、initializer_listでの初期化に対応しました。
  • Multi-Indexのhashed_indicesが、高速化しました。
  • Multiprecisionに、2進表現の浮動小数点数cpp_bin_floatが追加されました。
  • Optionalが、C++標準に提案されている仕様に対応しました。ムーブやemplace()のサポート、値にアクセスする新たな方法として、value()value_or()value_or_eval()のサポートが追加されました。(nulloptはまだ)
  • Smart Pointerの、make_shared()allocate_shared()に、配列のサポートが追加されました。
  • Threadに、C++標準のConcurrency TSで提案されているfutureの拡張であるwhen_any()when_all()が追加され、同様に提案されているexecutorが追加されました。

そのほか細かい変更は、リリースノートを参照してください。この記事の先頭に、日本語訳したリリースノートへのリンクを貼ってあります。

getかvalueか

std::optionalが提案された最初の時期、中身のデータを取り出す方法が、間接参照演算子しかありませんでした。そのあと、私が「boost::optionalにはget()メンバ関数があるが、こちらにはない。私はポインタインタフェースよりは、そちらを使いたい。」と提案したところ、get()メンバ関数の代わりに、value()メンバ関数が入りました。

その経緯としてはこういうものです。

  • shared_ptrunique_ptrには、生ポインタを取得するためのget()メンバ関数がある。
  • optionalは、見ようによってはスマートポインタと見なすこともできる。
  • optionalget()メンバ関数を入れるのであれば、スマートポインタのように、ポインタを返すべきではないか。
  • optionalget()はスマートポインタのインタフェースではなく、生データ(raw data, base data)を参照するセマンティクスなので、別名としてvalue()にしよう。

この結論を悪いとは思いませんが、私個人は、optionalboost::initializedstd::chrono::durationのようなラッパー型の、生データを参照するインタフェースを共通化したいと考えるので、私が作るクラスでは、get()メンバ関数に統一をしています。

先日の「チェック付き間接参照の提案 またの名をパターンマッチ」が受け入れられる場合は、生データを参照するインタフェースが共通していたほうがいいでしょうから、そのような話になったら、optionalのインタフェースも見直しになるかもしれません。間接参照演算子を共通インタフェースにはしたくないけどポインタも扱えるようにしたい、というなら、traitsのような中間インタフェースを用意することになるとは思います。

参照

immutable_vectorを作った

初期化時に要素の追加・変更を行い、そのあとに「もう変更しない」ことを明示できるvectorを作りました。ムーブがあるので簡単に作れた。

例:

#include <iostream>
#include <shand/immutable_vector.hpp>

int main()
{
    // 要素の追加・変更
    shand::vector_builder<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);

    // もう変更しない
    shand::immutable_vector<int> iv(std::move(v));

    for (int x : iv) {
        std::cout << x << std::endl;
    }
}

使い方としては、以下のようになります。

  • vector_builderを使い、要素の追加・変更をする。
    • これはただのstd::vectorの別名。
  • 追加・変更が終わったら、vector_builderimmutable_vectorにムーブする。
    • immutable_vectorは、mutableなインタフェースを持たないだけのstd::vectorのラッパー。

これらのクラスは、以下のように、ローカル変数でvector_builder、メンバ変数でimmutable_vectorを持つような状況を想定しています。

class X {
    shand::immutable_vector<T> data_;
public:
    void setupData()
    {
        shand::vector_builder<T> builder;
        …
        data_.build(std::move(builder));
    }
};

immutable_vectorコンストラクタのほかに、build()メンバ関数vector_builderからムーブできます。

チェック付き間接参照の提案 またの名をパターンマッチ

ポインタ操作では、以下のように「間接参照可能か(有効な値を指すポインタか)」をチェックしてから間接参照する、というのがよく行われます。

if (p) {
    T x = *p;
}

これを以下のように書けるようにしよう、というのがこの提案。

if (T x : p) {
}

つまり、間接参照ができるなら間接参照をして値を取り出す、までを一つのif文でやってしまおうというものです。

これは、値の判定と取り出しを同時に行う、ミニマムなパターンマッチと見なすことができます。

この機能は、多くの状況で便利に活用できます。

weak_ptrの場合

weak_ptrは、lock()メンバ関数を使用してshared_ptrオブジェクトを取り出します。その際、以下のようなコードを書くことになりますが、

if (shared_ptr<T> sp = wp.lock()) {
    f(*sp);
}

この状況で欲しいのはshared_ptrオブジェクトではなく、それを間接参照した要素ですので、今回提案されている構文を使えば、このようなコードがより簡潔に書けるようになります:

if (T& x : wp.lock()) {
    f(x);
}

while文の場合

有効な値を取り出せる間ループし続ける、という以下のようなコードも、

while (optional<message> m = try_read(i)) {
    process(*m);
}

この提案の構文をwhile文にも適用すれば、以下のように書けるようになります。

while (message m : try_read(i)) {
    process(m);
}

optionalは間接参照の演算子を持っているので、この構文が適用可能です。

この提案の今後

この提案の作者が、Clangで試しに実装してみるようです。今回の提案はだいぶ小さなものですが、非常に有用なものだと感じます。

Boost 1.56.0 Beta 1

Boost 1.56.0 Beta 1が出ました。

日本語リリースノートは、あと2つくらい残ってますが、だいたい訳してあります。

大きな問題がなければ、2週間くらいでリリースされるでしょう。