C++ MIX #6 開催案内

cppmix.connpass.com

次回のC++ MIXの日程が決まりました。

前回、カジュアルなディスカッションが思った以上に好評だったため、改善を入れつつ今回も継続して行います。

また、翔泳社から出版されている書籍『独習C++』がC++17対応で改訂されることになりましたので、出版記念を兼ねて Flast さんに発表していただきます。書籍を持ってきていただいた方には、著者がサインしてくれるでしょう。(私とzakさんも微力ながらレビューに参加させていただきました)

C++標準ライブラリの数学定数への道のり

C++20で数学定数が入ることが決まりましたね。やっと標準ライブラリの範囲で円周率を定数として使えるようになります。

ここまでの道のりですが、

  1. constexpr (C++11)
  2. 変数テンプレート (C++14)
  3. インライン変数 (C++17)
  4. 数学定数 (C++20)

とても長かったですね。

#include <iostream>
#include <numbers>

template <class T>
T degree_to_radian(T x)
{
    return x * std::numbers::pi_v<T> / static_cast<T>(180.0);
}

int main()
{
    float y = degree_to_radian(90.0f);
    std::cout << y << std::endl; // 1.5708
}

constexpr (C++11)

汎用的なコンパイル時計算ができるようになりました。

変数テンプレート (C++14)

constexpr関数では毎回値を計算することになるので、計算済みの値を変数として保持しておくために、テンプレートで変数定義ができるようになりました。

インライン変数 (C++17)

ヘッダファイルで変数を定義してもODR違反にならないよう、翻訳単位を跨いで実体をひとつにするために、インライン変数が導入されました。

これら全てを組み合わせてできた数学定数

// <numbers>ヘッダ
namespace std::numbers {
    // 先行宣言
    template<typename T> inline constexpr T pi_v;

    // 浮動小数点数だけ特殊化して定義
    template <FloatingPoint T>
    inline constexpr T pi_v<T> = (...計算...);

    // デフォルトでdouble
    inline constexpr double pi = pi_v<double>;
}

コンセプトも使われていますが、最終的にこうなりました。

std::numbers::piを使うとdouble型になり、std::numbers::pi_v<T>を使うと任意の浮動小数点数型になります。

非標準のM_PIマクロは昔からありましたが、これからは標準の数学定数が使えます。コンパイラが実装したらね!

次は数学関数のconstexpr化ですね。

Boost 1.71.0リリース

Boost 1.71.0がリリースされました。リリースノートの日本語訳 + 情報補完したものをboostjpサイトで公開しています。

新ライブラリは、Variant2。C++17で標準化されたstd::variantと互換性あるAPIを提供します。ただし、標準のものと違ってvaluelessにはなりません。互換性のためにvalueless_by_exception()関数は用意されますが、常にfalseを返します。

Boost.SmartPtrではenable_shared_from_thisクラスが再設計されました。weak_ptrが最初から考慮されるようになったことに加えて、CRTPを使用したクラステンプレートではなく非テンプレートな基本クラスになりました。boost::enable_shared_fromクラスを継承して使用し、boost::shared_from(this)boost::weak_from(this)のように使用します。

C++ MIX #5 の参加募集を開始しました

cppmix.connpass.com

2019/09/04 (水) になりました。

今回、チャレンジとしてカジュアルなディスカッションの時間を設けてみようと思います。勉強会という場は、モチベーションが高い人が集まっている場だと思うので、多くの参加者が発表を聴いてる、というのはもったいないな、と感じていました。

ディスカッションというと重く聞こえてしまい身構えてしまうかもしれませんが、自分の考えをだれかと話したいとか、深い議論に参加したい (聴いてるだけでもOK) とかができる場にしていきたいと考えています。

今回のチャレンジがうまくいくか、継続してできそうかはまだわかりませんが、一度やってみたいと思います。

C++ MIX #4 の参加募集を開始しました

2019/06/26に開催します。

今回から、勉強会ロゴを正式なものにしました。ロゴはzakさんに作っていただきました。プログラミングの魔導書の表紙、各記事のアイコンからずっとお世話になってます。

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

リリースノートは、いつものようにboostjpサイトで翻訳 + 情報補完したものを公開しています。

新ライブラリは、expectedのバリエーションを提供するOutcomeライブラリ、多次元ヒストグラムを扱うHistogramライブラリの2つです。

非推奨に近い状態だった線形代数ライブラリuBLASが、Google Summer of Codeでのコントリビュートを受けていろいろ機能追加されています。

リリースされたばかりのVisual Studio 2019はサポート対象外です。

C++20を相談しながら調べる会、を開催しました

C++20は3月の国際会議ですごく巨大なアップデートになって自分で調べるのがしんどくなってきました。

だれかに相談しながら調べたいな、と思って自社の会議室を使って少人数で集まっていました。

会の性質として、近くの人から相談がきたときに「このURLのページを見てみて」とかをさっと渡せるようにしたい、というのがあったので、Googleドキュメントを参加者間で共有して、メモ書きや課題の共有ができるようにしました。そのドキュメントは編集をロックして、イベントページに添付してあります。

参加者から、またやりたい、というリクエストがあったので、来月もやります。ずっと続く性質の会ではないかもしれませんが、困ったときに相談ができる相手がこういった場で作れると、別の機会でも協力しあえたりしてよいかと思います。

会の目的としては、アウトプットするためのインプットをする場がほしい、というものなので、自分が学んで満足したい、というのは会の範囲外としています。

lower_boundとupper_boundで区間抽出

lower_bound()upper_bound()でこんなことができたんだなーと発見できて楽しかったので、時間で区間を指定して抽出するのをやってみました。

簡易的なBoost.Interval Containerとして使えていいですね。

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

int main()
{
    std::vector<std::string> times = {
        "2018/12/31 00:00",
        "2019/01/01 00:01",
        "2019/01/01 01:15",
        "2019/01/01 03:30",
        "2019/01/01 08:23",
        "2019/01/01 10:50",
        "2019/01/01 13:20",
        "2019/01/01 15:30",
        "2019/01/01 18:00",
        "2019/01/03 23:59",
    };

    // 日付2019/01/01の午前中だけ取り出す
    auto first = std::lower_bound(times.begin(), times.end(), "2019/01/01 00:00");
    auto last  = std::upper_bound(times.begin(), times.end(), "2019/01/01 12:00");

    for (; first != last; ++first) {
        std::cout << *first << std::endl;
    }
}

出力:

2019/01/01 00:01
2019/01/01 01:15
2019/01/01 03:30
2019/01/01 08:23
2019/01/01 10:50

補足ですが、UTF-8とかの文字コードを指定しなくてもC++の規格で文字'0'から'9'までは順序が規定されているので、文字列の辞書順比較で日時の大小が決められます。月をJan、Febとかにしたら意図した動作にはなりません。数字以外の区切り文字とかが共通ならいけるので、「2019年01月01日」とかなら大丈夫です。月と日が2桁ゼロ埋めで揃えないといけない縛りとかはあります。

境界値のお試し。

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

int main()
{
    std::vector<std::string> times = {
        "2018/12/31 00:00",
        "2019/01/01 00:00",
        "2019/01/01 00:01",
        "2019/01/01 01:15",
        "2019/01/01 03:30",
        "2019/01/01 08:23",
        "2019/01/01 10:50",
        "2019/01/01 11:59",
        "2019/01/01 12:00",
        "2019/01/01 13:20",
        "2019/01/01 15:30",
        "2019/01/01 18:00",
        "2019/01/03 23:59",
    };

    // 日付2019/01/01の午前中だけ取り出す
    auto first = std::lower_bound(times.begin(), times.end(), "2019/01/01 00:00");
    auto last  = std::upper_bound(times.begin(), times.end(), "2019/01/01 12:00");

    for (; first != last; ++first) {
        std::cout << *first << std::endl;
    }
}

出力:

2019/01/01 00:00
2019/01/01 00:01
2019/01/01 01:15
2019/01/01 03:30
2019/01/01 08:23
2019/01/01 10:50
2019/01/01 11:59
2019/01/01 12:00