GCC 4.9がリリースされました

GCC 4.9.0 released, full of improved C++11 and C++14 features

C++14対応が主ですが、C++11にも、以下のサポート改善が入っています。

  • <regex>をサポート
  • <map><set><unordered_map><unordered_set>に、ステートフルアロケータのサポートを追加

<regex>は、昨年のGoogle Summer of Codeで学生さんが実装したものですね。お金を出してくれたGoogleと、実装してくれたTim Shenさんに感謝です。

オンラインコンパイラWandboxでも、すでにGCC 4.9を使える状態になっています。

BoostのGoogle Summer of Code 2014

C++

[gsoc2014] This year's students announced

学生を対象に、Googleから50万円くらいもらってオープンソース・ソフトウェアに貢献するGoogle Summer of Code。今年もはじまります。

Boost C++ Librariesでは、以下のプロジェクトが採択されました。

  • Anton Bikineev

    • Mentor: Christopher Kormanyos
    • Topic: Boost.Math Generalized Hypergeometric Functions
  • Ian Forbes

    • Mentor: Tim Blechmann
    • Topic: Boost.Thread Scheduled Executors
  • Louis Dionne

    • Mentor: Joel Falcou
    • Topic: A C++11 template metaprogramming library
  • Mark Lingle

    • Mentor: David Bellot
    • Topic: Boost.uBlas: Optimization via Smart Templating and a Tree Optimizer class
  • Roshan

    • Mentor: Kyle Lutz
    • Topic: Expand and Improve Boost.Compute
  • Saksham Maheshwari

    • Mentor: Stefan Seefeld
    • Topic: Boost.XML - A Standard XML Library
  • Thaler Benedek

    • Mentor: Vicente J. Botet Escriba
    • Topic: Boost.Pipeline
  • Vinícius dos Santos Oliveira

    • Mentor: Bjorn Reese
    • Topic: HTTP server on Boost

こういうことに興味がある学生の方は、来年申し込んでみるといいでしょう。

参照

Boost.Containerにrealloc相当の機能が入る予定

C++

これはrealloc()を拡張したい、というトピックですが、その中でBoost.Container作者のIonさんが「realloc()に相当する機能はBoost.Containerの1.56.0向けにすでに実装したよ」とおっしゃっていました。

std::vectorでは、push_back()で要素をどんどん追加していき、キャパシティが不足したら全要素が収まる新しい領域を確保します。realloc()相当の機能がアロケータにあれば、このような状況では領域を伸長すれば効率がよくなります。

realloc相当の機能に関する提案

アロケータにrealloc()相当の機能を追加する提案は現在、2つあります。

今回、Boost.Containerが実装したのは、N2045の方です。この方式では、アロケータクラスに、以下の関数を追加します。

enum allocation_type
{
    //Bitwise OR (|) combinable values
    allocate_new        = ...,
    expand_fwd          = ...,
    expand_bwd          = ...,
    shrink_in_place     = ...,
    nothrow_allocation  = ...
};

template <class T>
struct allocator {
  std::pair<pointer, bool>
      allocation_command(std::allocation_type command,
                         size_type limit_size,
                         size_type preferred_size,
                         size_type& received_size,
                         pointer reuse = 0);
};

コマンドによってメモリアロケーションの動作が代わります。expand_fwdexpand_bwdrealloc()相当になります。(allocate_newは今までのメモリアロケート)

実装方法

realloc()相当の機能と言っていますが、realloc()をそのままは使えません。realloc()は、領域の伸長に失敗したら新たな領域を作る、というところまでやってしまうので、細かい制御ができません。

std::vectorの内部実装として使うには、realloc()の前半部分である「領域の伸長を行う。(できなかったらヌルポインタか何かを返す。)」というところだけがほしいです。

そこで、Boost.Containerでは、dlmallocのソースを持ってきてBoost.Containerのリポジトリに入れてしまい、その上でdlmallocを拡張し、realloc()の前半部分を抜き出しています。dlmallocはCC0ライセンスなので、Boostのリポジトリに入れてしまってもライセンス上問題ありません。

使い方

realloc()相当の機能であるallocation_command()関数は、Boost.Containerのallocatorクラスに入っていますが、この機能は、アロケータにバージョンとして2を与えると有効になります。いままでは1で、デフォルトも1です。

#include <iostream>
#include <boost/container/allocator.hpp>
#include <boost/container/vector.hpp>

namespace cont = boost::container;

int main()
{
    cont::vector<int, cont::allocator<int, 2>> v;
    v.push_back(3);
    v.push_back(1);
    v.push_back(4);

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

出力:

3
1
4

バージョン2のアロケータを使用する場合、Boost.Containerのソース(dlmalloc)をビルドする必要があります。

結び

Boost.Containerは、標準コンテナの最新仕様を使用できることをひとつの目的としています。今回の機能はまさに、realloc()相当の機能に関する実装経験、使用経験を積む、いいケースだと感じます。

cpprefjp更新: scoped_allocator完了

C++

<scoped_allocator>

<scoped_allocator>ヘッダのリファレンス作成が完了しました。

これで、全52ヘッダ中、40ヘッダのリファレンスが完成しました。残り12ヘッダです。

また、これによって「ユーティリティライブラリの完成」というマイルストーンが完了しました。現在、次のマイルストーンを何にするかを、以下のGitHub Issueにて検討中です:

文字列を二分割する

C++

split(s, delimiter)だとsの中にdelimiterが2つ以上現れたらその数だけ分割されてしまうので、区切り文字を一度だけ認識し、二分割する関数を書きました。

#include <iostream>
#include <string>
#include <utility>
#include <tuple>

std::pair<std::string, std::string>
    bisect(const std::string& s, char delimiter)
{
    std::size_t pos = s.find_first_of(delimiter);

    return std::make_pair(
               s.substr(0, pos),
               s.substr(pos + 1));
}

int main()
{
    std::string a, b;
    std::tie(a, b) = bisect("aaa:bbb", ':');

    std::cout << a << std::endl;
    std::cout << b << std::endl;
}

出力:

aaa
bbb

はじめはsplit2()という名前の関数にしようかと思っていたのですが、@dplusplusさんからbisect()という名前を提案してもらい、カッコ良かったのでそれにしました。

mapのemplace

C++

C++11標準ライブラリのコンテナには、emplace()emplace_back()といったメンバ関数が追加されました。これらの関数は、コンテナの要素型のコンストラクタ引数を受け取り、要素型のオブジェクトをemplace()emplace_back()の内部で一度だけ作る、という効率化の役割を果たしてくれます。

std::vectoremplace_back()なら、以下のように、要素型Xコンストラクタ引数を渡すという、シンプルな使い方ができます。

struct X {
    X(int a, int b, int c) {}
};

std::vector<X> v;
v.emplace_back(1, 2, 3);

しかし、std::mapemplace()は、使うのがちょっと難しいです。mapはキーと値の組を扱うので、要素を追加する際、それぞれのコンストラクタ引数を受け取ろうとすると、引数の区切りがどこなのかがわからないのです。

std::map<X, Y> m;

// どこまでがXの引数で、どこからがYの引数?
m.emplace(1, 2, 3, 4, 5, 6);

引数の区切りを明確にするためには、それぞれの引数をタプルにパックして転送する必要があります。結果として、std::mapemplace()は以下のように使います。

#include <iostream>
#include <map>

struct X {
    int a, b, c;
    X(int a, int b, int c)
        : a(a), b(b), c(c) {}
};

bool operator<(const X& l, const X& r)
{
    return std::tie(l.a, l.b, l.c) < std::tie(r.a, r.b, r.c);
}

struct Y {
    Y(int d, int e, int f) {}
};

int main()
{
    std::map<X, Y> m;

    m.emplace(
        std::piecewise_construct,
        std::forward_as_tuple(1, 2, 3),  // Xのコンストラクタ引数
        std::forward_as_tuple(4, 5, 6)); // Yのコンストラクタ引数
}

std::forward_as_tuple()関数を使うと、tuple<T1&&, T2&&, T3&&...>のような、右辺値参照のタプルができます。

std::pairコンストラクタに、そのようなタプルを展開して各要素を構築するためのオーバーロードが用意されているので、それにおまかせすることになります。pairのこの構築方法については、以下のエントリを参照:

C++03で、特定のメンバ関数が存在するかを判定する

C++

Boost.TTIのhas_member_function機能を使って、特定のメンバ関数を持っているかを判定する。

C++11のSFINAE Expressionを使えない環境向け。

#include <boost/tti/has_member_function.hpp>

struct X {
    int foo(double, char);
};

namespace my_namespace {
    // foo()メンバ関数を持っているか判定するためのメタ関数を定義する
    BOOST_TTI_HAS_MEMBER_FUNCTION(foo)
}

int main()
{
    static_assert(
        my_namespace::has_member_function_foo<
            X,                               // 対象の型
            int,                             // 戻り値の型
            boost::mpl::vector<double, char> // パラメータの型
         >::value == true,
        "must be true");
}

参照

ユーザー定義型を直接Fusionシーケンスにしない選択肢

C++

ユーザー定義型を直接Boost.Spirit.Qiのパース結果として使いたい場合には通常、ユーザー定義型をBOOST_FUSION_ADAPT_STRUCTでFusionシーケンスとして見なせるようにします。

最近、ユーザー定義型をFusionシーケンスに変換する関数を用意するのもアリじゃないかと思えてきました。以下のプログラムでは、Point型をFusionシーケンスに変換するas_fusion_sequence()関数を持たせています。

#include <iostream>
#include <string>
#include <boost/fusion/include/vector_tie.hpp>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;
namespace fusion = boost::fusion;

struct Point {
    int x, y;

    fusion::vector<int&, int&> as_fusion_sequence()
    {
        return fusion::vector_tie(x, y);
    }
};

int main()
{
    const std::string input = "3,1";
    auto rule = boost::proto::deep_copy(qi::int_ >> ',' >> qi::int_);

    Point result;
    auto fused_result = result.as_fusion_sequence();

    std::string::const_iterator first = input.begin();
    if (qi::parse(first, input.end(), rule, fused_result)) {
        std::cout << result.x << ", " << result.y << std::endl;
    }
    else {
        std::cout << "parse error!" << std::endl;
    }
}

出力:

3, 1

こうしておくと、一つのユーザー定義型に対して、複数の解析方法(要素の順番を入れ替えたり)が定義できていい気がします。

Boost.Multiprecision 誤差の検証

C++

[Ruby]消費税計算にはBigDecimalを使いましょう

多倍長演算10進数型で演算を行えば、浮動小数点数の誤差がなくなるという話。C++の多倍長演算ライブラリであるBoost.Multiprecisionは無誤差であるというドキュメント上の規定はとくにないのですが、実際にどうなるのか検証してみました。

まずはdouble

まず、多倍長浮動小数型を使わず、doubleでやってみます。

#include <iostream>
#include <cmath>

int main()
{
    double a = 1800.0;
    double b = 1.08;

    double result = std::ceil(a * b);
    std::cout << result << std::endl; // 1944を期待する
}

出力:

1945

期待した1944ではなく、1945が出力されました。

cpp_dec_floatを使う

次に、Boost.Multiprecisionのcpp_dec_floatを使います。Boostのバージョンは1.55.0です。

#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>

namespace mp = boost::multiprecision;

using MyFloat = mp::cpp_dec_float_100;

int main()
{
    MyFloat a = 1800.0;
    MyFloat b = 1.08;

    MyFloat result = mp::ceil(a * b);
    std::cout << result << std::endl;
}

出力:

1945

こちらも期待した1944ではなく、1945になりました。

cpp_dec_floatを文字列初期化する

使い方が間違ってるみたいなので、値を文字列にしてみます。

#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>

namespace mp = boost::multiprecision;

using MyFloat = mp::cpp_dec_float_100;

int main()
{
    MyFloat a("1800.0");
    MyFloat b("1.08");

    MyFloat result = mp::ceil(a * b);
    std::cout << result << std::endl;
}

出力:

1944

期待した結果の1944になりました。

結び

最初にも書きましたが、この結果はcpp_dec_floatが無誤差演算であることを保証するものではありません。試しにやったらこういう結果になったというだけですので、ご注意を。

rationalはまだよくわかっていないので、使っていません。

Boost.Multiprecisionのnumberクラスのリファレンスページには、数学関数の演算でどれくらいの誤差が発生するかの表があるようです。

Non-member standard library function support - number class