Upgrade to Pro — share decks privately, control downloads, hide ads and more …

C++17の新機能 落穂拾い / new features of C++17 - gleaner

C++17の新機能 落穂拾い / new features of C++17 - gleaner

C++17 で追加されたライブラリ機能の紹介です。

一応調べながら書いてはいますが、力量の問題でいろいろ間違ってるかもです。
相変らず使用例が無いのは単なる力不足です…

Miutsuru kariya

March 28, 2019
Tweet

More Decks by Miutsuru kariya

Other Decks in Programming

Transcript

  1. 0

    View Slide

  2. C++17 の新機能
    落穂拾い
    2019/3/28 鳥頭かりやマン
    1

    View Slide

  3. *this のコピーキャプチャ
    2

    View Slide

  4. *this のコピーキャプチャ
    3
    P0018R0 : Lambda Capture of *this by Value
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0018r0.html
    P0018R1 : Lambda Capture of *this by Value
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0018r1.html
    P0018R2 : Lambda Capture of *this by Value as [=,*this]
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0018r2.html
    P0018R3 : Lambda Capture of *this by Value as [=,*this]
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0018r3.html

    View Slide

  5. *this のコピーキャプチャ
    4
    導入の背景

    View Slide

  6. *this のコピーキャプチャ
    導入の背景
    5
    *this だって
    コピーキャプチャ
    したい!
    まんまやん…

    View Slide

  7. *this のコピーキャプチャ
    導入の背景
    6
    今までの問題点
    • デフォルトコピーキャプチャを使うと、さもコピーキャプ
    チャされてる風に(?)メンバ変数名だけでアクセス可能
    になるが、実際には this ポインタがコピーされてるだけな
    ので、メンバ変数は実質参照キャプチャになっている。
    • *this をコピーキャプチャするには初期化キャプチャを使
    用して別の変数を導入する必要がある。
    • デフォルトコピーキャプチャと *this からの初期化キャプ
    チャを両方使用しても、間違ってメンバ変数名単体でアク
    セスすると参照アクセスになってしまう。

    View Slide

  8. *this のコピーキャプチャ
    導入の背景
    7
    #include
    struct S {
    S(int i) : i(i) {}
    int i;
    auto f() { return [=]{ return i; }; }
    };
    int main()
    {
    auto l = S(42).f();
    std::cout << l() << '¥n';
    }
    デフォルトコピーキャプチャでも、
    メンバ変数は this 経由でのアクセス
    なので、実質参照キャプチャ
    UB!!!
    デフォルトコピーキャプチャでも、
    メンバ変数は this 経由でのアクセス
    なので、実質参照キャプチャ

    View Slide

  9. *this のコピーキャプチャ
    導入の背景
    8
    #include
    struct S {
    S(int i) : i(i) {}
    int i;
    auto f() {
    return [self = *this]{ return self.i; };
    }
    };
    int main()
    {
    auto l = S(42).f();
    std::cout << l() << '¥n';
    }
    ナゾの変数 self を導入して、
    無理やりコピーキャプチャに。
    でもアクセスが面倒…
    ナゾの変数 self を導入して、
    無理やりコピーキャプチャに。
    でもアクセスが面倒…

    View Slide

  10. *this のコピーキャプチャ
    導入の背景
    9
    #include
    struct S {
    S(int i) : i(i) {}
    int i;
    auto f() { return [=, self = *this]{ return i; }; }
    };
    int main()
    {
    auto l = S(42).f();
    std::cout << l() << '¥n';
    }
    デフォルトコピーキャプチャでも、
    メンバ変数は this 経由でのアクセス
    なので、実質参照キャプチャ
    UB!!!
    デフォルトコピーキャプチャでも、
    メンバ変数は this 経由でのアクセス
    なので、実質参照キャプチャ
    せっかくナゾの変数 self を導入して
    も、デフォルトコピーキャプチャしてい
    ると this 経由でアクセスできちゃう…

    View Slide

  11. *this のコピーキャプチャ
    10
    対応

    View Slide

  12. *this のコピーキャプチャ
    対応
    11
    シンプルキャプチャに
    *this も指定できる
    ようにしよう!
    さすがにデフォルトの挙動は変えられなかったよ…

    View Slide

  13. *this のコピーキャプチャ
    対応
    12
    #include
    struct S {
    S(int i) : i(i) {}
    int i;
    auto f() { return [*this]{ return i; }; }
    };
    int main()
    {
    auto l = S(42).f();
    std::cout << l() << '¥n';
    }
    ナゾの変数 self を導入して、
    無理やりコピーキャプチャに。
    でもアクセスが面倒…
    ラムダキャプチャに *this を指定すると
    *this がコピーキャプチャされる。
    アクセスも簡単!

    View Slide

  14. *this のコピーキャプチャ
    対応
    13
    #include
    struct S {
    S(int i) : i(i) {}
    int i;
    auto f() { return [=, *this]{ return i; }; }
    };
    int main()
    {
    auto l = S(42).f();
    std::cout << l() << '¥n';
    }
    ナゾの変数 self を導入して、
    無理やりコピーキャプチャに。
    でもアクセスが面倒…
    デフォルトコピーキャプチャと一緒に
    使っても大丈夫!

    View Slide

  15. *this のコピーキャプチャ
    対応
    14
    #include
    struct S {
    S(int i) : i(i) {}
    int i;
    auto f() { return [&, *this]{ return i; }; }
    };
    int main()
    {
    auto l = S(42).f();
    std::cout << l() << '¥n';
    }
    ナゾの変数 self を導入して、
    無理やりコピーキャプチャに。
    でもアクセスが面倒…
    もちろん、デフォルト参照キャプチャと
    一緒に使っても大丈夫!

    View Slide

  16. *this のコピーキャプチャ
    15
    悲報

    View Slide

  17. *this のコピーキャプチャ
    悲報
    16
    • デフォルトコピーキャプチャでメンバ変数が実質
    参照キャプチャになるのは変わってない。
    • C++20 でデフォルトコピーキャプチャで this をコ
    ピーキャプチャする挙動が非推奨になるが、
    C++17 ではまだデフォルトコピーキャプチャ指定
    時に this を指定できない。

    View Slide

  18. *this のコピーキャプチャ
    悲報
    17
    #include
    struct S {
    S(int i) : i(i) {}
    int i;
    auto f() { return [=]{ return i; }; }
    };
    int main()
    {
    auto l = S(42).f();
    std::cout << l() << '¥n';
    }
    デフォルトコピーキャプチャでも、
    メンバ変数は this 経由でのアクセス
    なので、実質参照キャプチャ
    UB!!!
    デフォルトコピーキャプチャだけだと、
    今までと何も変わってない…

    View Slide

  19. *this のコピーキャプチャ
    悲報
    18
    #include
    struct S {
    S(int i) : i(i) {}
    int i;
    auto f() { return [=]{ return i; }; }
    };
    int main()
    {
    auto s = S(42);
    auto l = s.f();
    std::cout << l() << '¥n';
    }
    デフォルトコピーキャプチャでも、
    メンバ変数は this 経由でのアクセス
    なので、実質参照キャプチャ
    C++20 だと
    デフォルトコピーキャプチャだけで
    this にアクセスするのは非推奨…

    View Slide

  20. *this のコピーキャプチャ
    悲報
    19
    #include
    struct S {
    S(int i) : i(i) {}
    int i;
    auto f() { return [=, this]{ return i; }; }
    };
    int main()
    {
    auto s = S(42);
    auto l = s.f();
    std::cout << l() << '¥n';
    }
    デフォルトコピーキャプチャでも、
    メンバ変数は this 経由でのアクセス
    なので、実質参照キャプチャ
    C++20 からは
    このように書くのが良いが、
    C++17 ではこの書き方はエラー

    View Slide

  21. *this のコピーキャプチャ
    悲報
    20
    結論
    デフォルトキャプチャ
    使うのは避けよう!

    View Slide

  22. *this のコピーキャプチャ
    21


    制作・著作
    ━━━━━
    ⓃⒽⓀ

    View Slide

  23. emplace の戻り値型変更
    22

    View Slide

  24. emplace の戻り値型変更
    23
    P0084R0 Emplace Return Type
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0084r0.pdf
    P0084R1 Emplace Return Type (Revision 1)
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0084r1.pdf
    P0084R2 Emplace Return Type (Revision 2)
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0084r2.pdf

    View Slide

  25. emplace の戻り値型変更
    24
    導入の背景

    View Slide

  26. emplace の戻り値型変更
    導入の背景
    25
    emplace_front や
    emplace_back の直後にその
    要素アクセスすることが多い
    んだが、こいつらの戻り値型
    が void でまんどくさい…
    普通の emplace は iterator とか返ってくるのにね…

    View Slide

  27. emplace の戻り値型変更
    導入の背景
    26
    ペーパーに載ってた例
    // ① 格納してすぐにメンバ関数呼び出し
    my_container.emplace_back(…);
    my_container.back().do_something(…);
    // ② 格納してすぐに関数に引き渡し(バンドじゃないよ(分かったらおっさん
    my_container.emplace_back(…);
    do_something_else(my_container.back());
    // ➂ デフォルト構築してすぐにファイルから読み込み
    my_container.emplace_back();
    my_container.back().read(file_stream);

    View Slide

  28. emplace の戻り値型変更
    27
    対応

    View Slide

  29. emplace の戻り値型変更
    対応
    28
    要素への
    参照返す
    ようにしよ
    575(無理やり
    iterator じゃないんだ…

    View Slide

  30. emplace の戻り値型
    対応
    29
    対象
    1.シーケンスコンテナの
    emplace_front、emplace_backという
    名のメンバ関数
    2.コンテナアダプタの queue::emplace、
    stack::emplace
    priority_queue::emplace は入らないのね…

    View Slide

  31. emplace の戻り値型変更
    対応
    30
    ペーパーに載ってた例(改)
    // ① 格納してすぐにメンバ関数呼び出し
    my_container.emplace_back(…).do_something(…);
    // ② 格納してすぐに関数に引き渡し
    do_something_else(my_container.emplace_back(…));
    // ➂ デフォルト構築してすぐにファイルから読み込み
    my_container.emplace_back().read(file_stream);

    View Slide

  32. emplace の戻り値型変更
    対応
    31
    push 系はやらないの?

    push するって事は既にオブジェクト持ってる
    から不要なことが多いし、どうしても格納後オ
    ブジェクトにアクセスしたければ emplace 使
    えばいいっしょ(ペーパーより超訳)

    View Slide

  33. emplace の戻り値型変更
    対応
    32
    下記の2点がよくわかりませんでした…
    • 他の emplace 系の戻り値型は iterator な
    のに何で参照なの?
    • 何で std::priority_queue::emplace は対象
    外なの?
    教えて!エロい人!!!

    View Slide

  34. emplace の戻り値型変更
    33


    制作・著作
    ━━━━━
    ⓃⒽⓀ

    View Slide

  35. 単純な文字列変換
    34

    View Slide

  36. 単純な文字列変換
    35
    N4412: Shortcomings of iostreams
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4412.html
    P0067R0: Elementary string conversions
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0067r0.html
    P0067R1: Elementary string conversions, revision 1
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0067r1.html
    P0067R2: Elementary string conversions, revision 2
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0067r2.html
    P0067R3: Elementary string conversions, revision 2
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0067r3.html
    P0067R4: Elementary string conversions, revision 4
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0067r4.html
    P0067R5: Elementary string conversions, revision 5
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0067r5.html

    View Slide

  37. 単純な文字列変換
    36
    導入の背景

    View Slide

  38. 単純な文字列変換
    導入の背景
    37
    既存ライブラリの問題点
    • 書式指定文字列うぜぇ
    • 動的メモリ割当強制うぜぇ
    • ロケールうぜぇ
    • 仮想関数呼び出しうぜぇ
    • バッファオーバーラン怖ぇ
    • 入力文字列のエラー分かんねぇのうぜぇ
    • 入力文字列のスペース勝手に無視すんのうぜぇ
    • 頭の0x勝手に解釈すんのうぜぇ

    View Slide

  39. 単純な文字列変換
    導入の背景
    38
    既存ライブラリの問題点
    結論
    うぜぇ
    ちょっと怖ぇ

    View Slide

  40. 単純な文字列変換
    導入の背景
    39
    既存機能 うぜぇとこ
    sprintf ロケール、書式指定文字列、バッファオーバーラン
    snprintf ロケール、書式指定文字列
    sscanf ロケール、書式指定文字列
    atol ロケール、エラー発生不明
    strtol ロケール、空白無視、0x勝手に解釈
    strstream ロケール、空白無視
    stringstream ロケール、空白無視、動的メモリ割当
    num_put /
    num_get facets
    ロケール、仮想関数呼び出し
    to_string ロケール、動的メモリ割当
    stoi etc.
    ロケール、動的メモリ割当、空白無視、0x勝手に解釈、
    エラー時例外

    View Slide

  41. 単純な文字列変換
    導入の背景
    40
    オレはただ単純に
    数値と文字列とを
    変換したいだけ
    なんだ!!!1!

    View Slide

  42. 単純な文字列変換
    41
    対応

    View Slide

  43. 単純な文字列変換
    対応
    42
    単純な
    文字列変換
    追加しよ
    575(無理やり
    まんま…

    View Slide

  44. 単純な文字列変換
    対応
    43
    新規ライブラリの特徴
    • 書式指定は文字列じゃない
    • 動的メモリ割当しない
    • ロケール無視
    • 仮想関数呼び出ししない
    • バッファオーバーランしない
    • 戻り値でエラー返す
    • 入力文字列のスペース無視しない
    • 頭の0x解釈しない

    View Slide

  45. 単純な文字列変換
    対応
    44
    文字列から数値への変換
    from_chars_result
    from_chars(const char* first, const char* last,
    INT※1& value, int base = 10);
    from_chars_result
    from_chars(const char* first, const char* last,
    FLOAT※2& value,
    chars_format fmt = chars_format::general);
    ※1 符号付き整数型、符号無し整数型、charのいずれか。
    整数型全部じゃないよ。(bool とか char32_t とかは無い)
    ※2 任意の浮動小数点型。

    View Slide

  46. 単純な文字列変換
    対応
    45
    文字列から数値への変換
    struct from_chars_result {
    const char* ptr; //数値として解釈できない文字へのポインタ
    errc ec; //変換失敗した場合のエラーコード
    };
    enum class chars_format {
    scientific = 値は未規定, // %e と同じ
    fixed = 値は未規定, // %f と同じ
    hex = 値は未規定, // %a とだいたい同じ
    general = fixed | scientific // %g と同じ
    };

    View Slide

  47. 単純な文字列変換
    対応
    46
    数値から文字列への変換
    to_chars_result to_chars(char* first, char* last,
    INT※1 value, int base = 10);
    to_chars_result to_chars(char* first, char* last,
    FLOAT※2 value);
    to_chars_result to_chars(char* first, char* last,
    FLOAT※2 value, chars_format fmt);
    to_chars_result to_chars(char* first, char* last,
    FLOAT※2 value, chars_format fmt,
    int precision);

    View Slide

  48. 単純な文字列変換
    対応
    47
    数値から文字列への変換
    struct to_chars_result {
    char* ptr; // 出力された最後の文字の次へのポインタ
    errc ec; // 変換失敗した場合のエラーコード
    };

    View Slide

  49. 単純な文字列変換
    対応
    48
    重要
    なんと新規ヘッダ

    View Slide

  50. 単純な文字列変換
    49
    使い方

    View Slide

  51. 単純な文字列変換
    使い方
    50
    // 文字⇒数値変換
    const char s[] = "42kg";
    int i = 0;
    auto r = std::from_chars(s, s + sizeof(s) - 1, i);
    assert(i == 42);
    assert(r.ptr == s + 2);
    assert(r.ec == std::errc{});
    ※ r.ptr は数値として解釈できない文字(この場合は"k")を指す。
    (エラーではない)
    ちなみに、ここでは説明のため敢えて r で受けてるけど普通は構造化束縛使うよね…

    View Slide

  52. 単純な文字列変換
    使い方
    51
    // マイナス符号
    const char s[] = "-42g";
    int i = 0;
    auto r = std::from_chars(s, s + sizeof(s) - 1, i);
    assert(i == -42);
    assert(r.ptr == s + 3);
    assert(r.ec == std::errc{});

    View Slide

  53. 単純な文字列変換
    使い方
    52
    // プラス符号はNG
    const char s[] = "+42";
    int i = 114'514;
    auto r = std::from_chars(s, s + sizeof(s) - 1, i);
    assert(i == 114'514);
    assert(r.ptr == s);
    assert(r.ec == std::errc::invalid_argument);
    ※ エラーの時は i は変わらず、r.ptr は数値として解釈できない文
    字(この場合は"+")を指す。

    View Slide

  54. 単純な文字列変換
    使い方
    53
    // 数値がデカすぎる場合もNG
    const char s[] = "12345678901234567890";
    int i = 42;
    auto r = std::from_chars(s, s + sizeof(s) - 1, i);
    assert(i == 42);
    assert(r.ptr == s + sizeof(s) - 1);
    assert(r.ec == std::errc::result_out_of_range);
    ※ この場合も、r.ptr は数値として解釈できない文字を指すので、最
    後の数字の次の文字(つまり終端)を指している。
    (変換対象の文字の次ではない)

    View Slide

  55. 単純な文字列変換
    使い方
    54
    // もちろん16進数はOK
    const char s[] = "DEADBEEF";
    int i = 42;
    auto r = std::from_chars(s, s + sizeof(s) - 1, i, 16);
    assert(i == 0xDEAD'BEEF);
    assert(r.ptr == s + 8);
    assert(r.ec == std::errc{});

    View Slide

  56. 単純な文字列変換
    使い方
    55
    // 16進数でも頭の"0x"はNG
    const char s[] = "0xDEADBEEF";
    int i = 42;
    auto r = std::from_chars(s, s + sizeof(s) - 1, i, 16);
    assert(i == 0);
    assert(r.ptr == s + 1);
    assert(r.ec == std::errc{});
    ※ エラーじゃなくて、先頭の0だけ変換されてる。(わりとワナ)

    View Slide

  57. 単純な文字列変換
    使い方
    56
    // ナゾの36進数までOK
    const char s[] = "1Z1z";
    int i = 42;
    auto r = std::from_chars(s, s + sizeof(s) - 1, i, 36);
    assert(i == 92'087);
    assert(r.ptr == s + 4);
    assert(r.ec == std::errc{});

    View Slide

  58. 単純な文字列変換
    使い方
    57
    // 浮動小数点型
    const char s[] = "42.195km";
    double d = 0;
    auto r = std::from_chars(s, s + sizeof(s) - 1, d);
    assert(d == 42.195);
    assert(r.ptr == s + 6);
    assert(r.ec == std::errc{});

    View Slide

  59. 単純な文字列変換
    使い方
    58
    // 浮動小数点型もプラス符号はNG
    const char s[] = "+42.195km";
    double d = 114'514;
    auto r = std::from_chars(s, s + sizeof(s) - 1, d);
    assert(d == 114'514);
    assert(r.ptr == s);
    assert(r.ec == std::errc::invalid_argument);

    View Slide

  60. 単純な文字列変換
    使い方
    59
    // 指数部のプラス符号はOK(もちろんなくてもOK)
    const char s[] = "2.99792458e+8m/s";
    double d = 0;
    auto r = std::from_chars(s, s + sizeof(s) - 1, d);
    assert(d == 2.997'924'58e+8);
    assert(r.ptr == s + 13);
    assert(r.ec == std::errc{});

    View Slide

  61. 単純な文字列変換
    使い方
    60
    // fmtがscientificの場合は指数部が無いとNG
    const char s[] = "299792458m/s";
    double d = 0;
    auto r = std::from_chars(s, s + sizeof(s) - 1, d,
    std::chars_format::scientific);
    assert(d == 0);
    assert(r.ptr == s);
    assert(r.ec == std::errc::invalid_argument);
    ※ 形式エラーの場合は ptr は先頭を指すらしい。(たぶん使わない)

    View Slide

  62. 単純な文字列変換
    使い方
    61
    // fmtがhexならみんな大好き16進浮動小数点も行けるけど、
    // こちらも先頭の0xはNG
    const char s[] = "CAFE.BABEp+15Java";
    double d = 0;
    auto r = std::from_chars(s, s + sizeof(s) - 1, d,
    std::chars_format::hex);
    assert(d == 0xCAFE.BABEp+15); //つまり、1.702'845'791e+9
    assert(r.ptr == s + 13);
    assert(r.ec == std::errc{});

    View Slide

  63. 単純な文字列変換
    使い方
    62
    // 数値⇒文字変換
    int i = 42;
    char s[10];
    auto r = std::to_chars(s, s + sizeof(s), i);
    assert("42"sv == std::string_view(s, r.ptr - s));
    assert(r.ec == std::errc{});
    ※ プラス符号は付かない。(付ける方法は無い)
    出力は '¥0' で終端されるわけではないので注意!

    View Slide

  64. 単純な文字列変換
    使い方
    63
    // もちろん16進数もOK
    int i = 42;
    char s[10];
    auto r = std::to_chars(s, s + sizeof(s), i, 16);
    assert("2a"sv == std::string_view(s, r.ptr - s));
    assert(r.ec == std::errc{});
    ※ 頭に"0x"は付かない。(付ける方法は無い)
    英文字の出力は小文字。(大文字バージョンは無い)

    View Slide

  65. 単純な文字列変換
    使い方
    64
    // もちろん(?)ナゾの36進数まで行ける
    int i = 92'087;
    char s[10];
    auto r = std::to_chars(s, s + sizeof(s), i, 36);
    assert("1z1z"sv == std::string_view(s, r.ptr - s));
    assert(r.ec == std::errc{});

    View Slide

  66. 単純な文字列変換
    使い方
    65
    // バッファが足りないとエラー
    int i = 114'514;
    char s[5];
    auto r = std::to_chars(s, s + sizeof(s), i);
    assert(r.ptr == s + sizeof(s));
    assert(r.ec == std::errc::value_too_large);
    ※ 変換エラーの場合は ptr は最後を指すらしい。(たぶん使わない)
    変換エラーの場合、バッファの中身は未規定

    View Slide

  67. 単純な文字列変換
    使い方
    66
    // 浮動小数点
    double d = 100'000;
    char s[10];
    auto r = std::to_chars(s, s + sizeof(s), d);
    assert(r.ec == std::errc{});
    assert("1e+05"sv == std::string_view(s, r.ptr - s));
    ※ フォーマットを指定しないと、ロケール C の printf で %f と %e
    で変換した場合に文字列が短くなる方になる。
    同じ長さの場合には %f 優先。
    printf の %g とは違うので注意。

    View Slide

  68. 単純な文字列変換
    使い方
    67
    // 浮動小数点
    double d1 = 3.141592653589793238462643383279;
    char s[50];
    auto r1 = std::to_chars(s, s + sizeof(s), d1);
    assert(r1.ec == std::errc{});
    double d2 = 0;
    auto r2 = std::from_chars(s, r1.ptr, d2);
    assert(d1 == d2);
    assert(r2.ec == std::errc{});
    ※ 浮動小数点数は、文字列化の際に精度を指定しない場合、ラウンド
    トリップして結果が等しくなるように処理される。
    フォーマットを指定した場合でも同じ。(ここも printf と違う)

    View Slide

  69. 単純な文字列変換
    使い方
    68
    // 浮動小数点
    double d = 3.141592653589793238462643383279;
    char s[100];
    auto r = std::to_chars(s, s + sizeof(s), d,
    std::chars_format::general, 3);
    assert(r.ec == std::errc{});
    assert("3.14"sv == std::string_view(s, r.ptr - s));
    ※ 精度の指定内容は printf の対応する書式と同じ。
    (精度の指定はできるけど幅の指定はできないよ)

    View Slide

  70. 単純な文字列変換
    使い方
    69
    // みんな大好き16進浮動小数点もOK
    double d = 0.0625;
    char s[10];
    auto r = std::to_chars(s, s + sizeof(s), d,
    std::chars_format::hex);
    assert(r.ec == std::errc{});
    assert("1p-04"sv == std::string_view(s, r.ptr - s));
    ※ 頭に0xは付かない。

    View Slide

  71. 単純な文字列変換
    70
    悲報

    View Slide

  72. 単純な文字列変換
    悲報
    71
    GCC も Clang も
    整数しか対応して
    ない…

    View Slide

  73. 単純な文字列変換
    悲報
    72
    何と VC++ 14.16 は
    浮動小数点数も
    それなりに
    対応してる!
    すごいぞ VC++!
    まだ不完全ではあるけど、ちょっと見直した…

    View Slide

  74. 単純な文字列変換
    73


    制作・著作
    ━━━━━
    ⓃⒽⓀ

    View Slide

  75. 検索アルゴリズム
    74

    View Slide

  76. 検索アルゴリズム
    75
    N3411: Additional Searching Algorithms
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3411.pdf
    N3606: Extending std::search to use Additional Searching Algorithms
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3606.html
    N3703: Extending std::search to use Additional Searching Algorithms
    (Version 3)
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3703.html
    P0253R0: Fixing a design mistake in the searchers interface in Library
    Fundamentals
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0253r0.pdf
    P0253R1: Fixing a design mistake in the searchers interface in Library
    Fundamentals
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0253r1.pdf

    View Slide

  77. 検索アルゴリズム
    76
    導入の背景

    View Slide

  78. 検索アルゴリズム
    導入の背景
    77
    std::search ってとって
    も便利だけど、もっと
    いいアルゴリズムも
    アルゴリズム

    View Slide

  79. 検索アルゴリズム
    導入の背景
    78
    もっといい
    アルゴリズム
    ???

    View Slide

  80. 検索アルゴリズム
    導入の背景
    79
    もっといいアルゴリズムの例
    • Boyer-Moore
    • Boyer-Moore-Horspool
    結構有名らしい…(小並感
    アルゴリズムの中身については聞かないでください…

    View Slide

  81. 検索アルゴリズム
    導入の背景
    80
    導入にあたっての懸念点
    もっといいアルゴリズム達は、
    検索パータンに対する前処理を
    必要とするので、前処理結果を
    保存できないともったいない。

    View Slide

  82. 検索アルゴリズム
    導入の背景
    81
    でも現在の
    std::searchのインタ
    フェースは…

    View Slide

  83. 検索アルゴリズム
    導入の背景
    82
    template
    ForwardIterator1
    search(ForwardIterator1 first1, ForwardIterator1 last1,
    ForwardIterator2 first2, ForwardIterator2 last2);
    templateclass BinaryPredicate>
    ForwardIterator1
    search(ForwardIterator1 first1, ForwardIterator1 last1,
    ForwardIterator2 first2, ForwardIterator2 last2,
    BinaryPredicate pred);
    ※ [first1, last1) が検索される範囲、[first2, last2) が検索パ
    ターン範囲なので、前処理結果を保存できる余地が無さそう…

    View Slide

  84. 検索アルゴリズム
    83
    対応

    View Slide

  85. 検索アルゴリズム
    対応
    84
    • さっきの2つのアルゴリズムは
    標準でサポートしよう!
    • std::search のオーバーロードだ
    けじゃなくて、オブジェクトイン
    タフェースも追加しよう!

    View Slide

  86. 検索アルゴリズム
    対応
    85
    オブジェクト
    インタフェース
    ???

    View Slide

  87. 検索アルゴリズム
    対応
    86
    1. 検索パターン範囲を、コン
    ストラクタの引数にして、検
    索オブジェクトを作る
    2. 検索対象範囲を、関数呼び
    出し演算子の引数にして、
    実際に検索する

    View Slide

  88. 検索アルゴリズム
    対応
    87
    使い方イメージ
    auto s = u8"柿"sv;
    auto bm = std::boyer_moore_searcher(begin(s), end(s));
    auto t = u8"杮杮杮杮杮杮杮杮杮杮柿杮杮杮杮杮杮杮杮杮杮"sv;
    auto p = bm(begin(t), end(t));
    std::cout << p.first - begin(t) << ", "
    << p.second - begin(t) << '¥n';

    View Slide

  89. 検索アルゴリズム
    対応
    88
    使い方イメージ
    auto s = u8"柿"sv;
    auto bm = std::boyer_moore_searcher(begin(s), end(s));
    auto t = u8"杮杮杮杮杮杮杮杮杮杮柿杮杮杮杮杮杮杮杮杮杮"sv;
    auto p = bm(begin(t), end(t));
    std::cout << p.first - begin(t) << ", "
    << p.second - begin(t) << '¥n';
    検索パターン範囲をッ、コンストラクタの引数
    にしてッ、検索オブジェクトを作るッ!!!
    ※ ここでは Boyer-Moore アルゴリズム

    View Slide

  90. 検索アルゴリズム
    対応
    89
    使い方イメージ
    auto s = u8"柿"sv;
    auto bm = std::boyer_moore_searcher(begin(s), end(s));
    auto t = u8"杮杮杮杮杮杮杮杮杮杮柿杮杮杮杮杮杮杮杮杮杮"sv;
    auto p = bm(begin(t), end(t));
    std::cout << p.first - begin(t) << ", "
    << p.second - begin(t) << '¥n';
    検索対象範囲をッ、関数呼び出し演算子の引数に
    してッ、実際に検索するッ!!!
    同じオブジェクトで何度でも検索できるぞッ!!!

    View Slide

  91. 検索アルゴリズム
    対応
    90
    使い方イメージ
    auto s = u8"柿"sv;
    auto bm = std::boyer_moore_searcher(begin(s), end(s));
    auto t = u8"杮杮杮杮杮杮杮杮杮杮柿杮杮杮杮杮杮杮杮杮杮"sv;
    auto p = bm(begin(t), end(t));
    std::cout << p.first - begin(t) << ", "
    << p.second - begin(t) << '¥n';
    検索結果はッ、見つかった場所の最初と最後(+1)
    がッ、イテレータのペアで返ってくるッ!!!
    ※ 見つからなかったらどっちも検索対象範囲の最後

    View Slide

  92. 検索アルゴリズム
    対応
    91
    使い方イメージ
    auto s = u8"柿"sv;
    auto bm = std::boyer_moore_searcher(begin(s), end(s));
    auto t = u8"杮杮杮杮杮杮杮杮杮杮柿杮杮杮杮杮杮杮杮杮杮"sv;
    auto p = bm(begin(t), end(t));
    std::cout << p.first - begin(t) << ", "
    << p.second - begin(t) << '¥n';
    上記の場合、「柿」は10文字目なので、出力は「30, 33」になる。
    (文字列リテラルがUTF-8なので1文字3バイトである事に注意!)

    View Slide

  93. 検索アルゴリズム
    対応
    92
    使い方イメージ
    auto s = u8"柿"sv;
    auto bm = std::boyer_moore_searcher(begin(s), end(s));
    auto t = u8"杮杮杮杮杮杮杮杮杮杮柿杮杮杮杮杮杮杮杮杮杮"sv;
    auto p = bm(begin(t), end(t));
    std::cout << p.first - begin(t) << ", "
    << p.second - begin(t) << '¥n';
    上記の場合、「柿」は10文字目なので、出力は「30, 33」になる。
    (文字列リテラルがUTF-8なので1文字3バイトである事に注意!)
    あ、「柿」(かき)はこの文字だけで、あとは「杮」(こけら)です。
    見ればわかると思うけど(?)、念のため。

    View Slide

  94. 検索アルゴリズム
    93
    検索オブジェクトの
    種類

    View Slide

  95. 検索アルゴリズム
    検索オブジェクトの種類
    94
    標準では以下の3つをサポート
    • デフォルト
    • Boyer-Moore
    • Boyer-Moore-Horspool

    View Slide

  96. 検索アルゴリズム
    検索オブジェクトの種類
    95
    デフォルト
    愚直に検索。(今までの std::search と同じ※)
    前処理しないので、検索パターンや検索対象範囲
    が短い場合、検索を1回しかしない場合等ではわり
    と有利。
    余計なメモリを食わない。
    イテレータが前方イテレータでOK。
    名前が簡単なのでとても良い。(個人の感想です)
    ※ std::search と同じと書いたけど、実は規格書には何
    も書いてない…

    View Slide

  97. 検索アルゴリズム
    検索オブジェクトの種類
    96
    templateclass BinaryPredicate = equal_to<>>
    class default_searcher {
    public:
    default_searcher(
    ForwardIterator1 pat_first,
    ForwardIterator1 pat_last,
    BinaryPredicate pred = BinaryPredicate());
    template
    pair
    operator()(ForwardIterator2 first,
    ForwardIterator2 last) const;
    };

    View Slide

  98. 検索アルゴリズム
    検索オブジェクトの種類
    97
    Boyer-Moore
    Boyer-Moore法で検索。
    ワーストケースがO(n)。(nは検索対象範囲の長さ)
    前処理時にテーブルを2つ作るので、前処理時間
    がかかるし、結構メモリも食う。
    検索パターンや検索対象範囲が長い場合、あるい
    は、同じ検索パターンで何度も検索する場合には
    有利。
    ランダムアクセスイテレータが必要。
    名前が難しいので辛い。(個人の(ry

    View Slide

  99. 検索アルゴリズム
    検索オブジェクトの種類
    98
    templateclass Hash = hashiterator_traits::value_type>,
    class BinaryPredicate = equal_to<>>
    class boyer_moore_searcher {
    public:
    boyer_moore_searcher(
    RandomAccessIterator1 pat_first,
    RandomAccessIterator1 pat_last,
    Hash hf = Hash(),
    BinaryPredicate pred = BinaryPredicate());
    template
    pair
    operator()(RandomAccessIterator2 first,
    RandomAccessIterator2 last) const;
    };

    View Slide

  100. 検索アルゴリズム
    検索オブジェクトの種類
    99
    Boyer-Moore-Horspool
    Boyer-Moore-Horspool法で検索。
    ワーストケースは愚直なのと一緒だが、大抵は
    O(n)でいける。
    前処理時に作るテーブルは1つだけなので、Boyer-
    Moore法よりは前処理時間もメモリ食わない。
    なので、わりとバランスがいいのかな?
    ランダムアクセスイテレータが必要。
    名前がとても難しいのでとても辛い。(個人の(ry

    View Slide

  101. 検索アルゴリズム
    検索オブジェクトの種類
    100
    templateclass Hash = hashiterator_traits::value_type>,
    class BinaryPredicate = equal_to<>>
    class boyer_moore_horspool_searcher {
    public:
    boyer_moore_horspool_searcher(
    RandomAccessIterator1 pat_first,
    RandomAccessIterator1 pat_last,
    Hash hf = Hash(),
    BinaryPredicate pred = BinaryPredicate());
    template
    pair
    operator()(RandomAccessIterator2 first,
    RandomAccessIterator2 last) const;
    };

    View Slide

  102. 検索アルゴリズム
    検索オブジェクトの種類
    101
    重要
    イテレータの参照先はオブ
    ジェクト作る時と検索する時
    で変わったらダメ!!!
    変えちゃうと検索が発狂しちゃう…

    View Slide

  103. 検索アルゴリズム
    検索オブジェクトの種類
    102
    重要その2

    じゃなくて

    View Slide

  104. 検索アルゴリズム
    103
    悲報

    View Slide

  105. 検索アルゴリズム
    悲報
    104
    Clang はまだ(?)
    default_searcher
    しか対応してない…
    VC++は対応してるぞ!すごいぞ!

    View Slide

  106. 検索アルゴリズム
    105


    制作・著作
    ━━━━━
    ⓃⒽⓀ

    View Slide

  107. 検索アルゴリズム
    106
    あれ?
    std::search の
    オーバーロード
    は?

    View Slide

  108. 検索アルゴリズム
    107
    template
    ForwardIterator
    search(ForwardIterator first,
    ForwardIterator last,
    const Searcher& searcher);
    以下と一緒
    return searcher(first, last).first;
    second 棄てられとる…

    View Slide

  109. 検索アルゴリズム
    108
    std::search は
    要らない子…
    ※ 実行ポリシー指定できるヤツを除く

    View Slide

  110. 検索アルゴリズム
    109


    制作・著作
    ━━━━━
    ⓃⒽⓀ

    View Slide

  111. コンテナの不完全型
    サポート
    110

    View Slide

  112. コンテナの不完全型サポート
    111
    N3890 Container
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3890.html
    N4056 Minimal incomplete type support for standard containers
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4056.html
    N4371 Minimal incomplete type support for standard containers, revision 2
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4371.html
    N4390 Minimal incomplete type support for standard containers, revision 3
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4390.html
    N4510 Minimal incomplete type support for standard containers, revision 4
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4510.html

    View Slide

  113. コンテナの不完全型サポート
    112
    導入の背景

    View Slide

  114. コンテナの不完全型サポート
    導入の背景
    113
    不完全型の
    コンテナが
    使いたい!

    View Slide

  115. コンテナの不完全型サポート
    導入の背景
    114
    ???

    View Slide

  116. コンテナの不完全型サポート
    導入の背景
    115
    こんなの出来たらうれしいよね? by 提案ペーパー
    struct Entry {
    std::list messages; // ここではまだ
    ... // Entry が不完全型
    };
    要は、要素型の定義がまだ不完全な状態でもコンテ
    ナを使いたい。
    それ、Boost.Container で出来るよ

    View Slide

  117. コンテナの不完全型サポート
    116
    対応

    View Slide

  118. コンテナの不完全型サポート
    対応
    117
    ただし、条件付き…

    View Slide

  119. コンテナの不完全型サポート
    対応
    118
    条件①
    対応コンテナは以下の3つだけ
    vector
    list
    forward_list
    何で絞ったのかな…

    View Slide

  120. コンテナの不完全型サポート
    対応
    119
    条件②
    アロケータが以下を満たす
    1. アロケータが完全型
    2. 対応する allocator_traits のメン
    バ型は value_type 以外完全型
    アロケータ完全性、と言うらしい…

    View Slide

  121. コンテナの不完全型サポート
    対応
    120
    条件➂
    コンテナの、特殊化されたいず
    れかのメンバが、参照される前
    には完全型になっている
    まぁそりゃあ使うときに完全型じゃないと困るよね…

    View Slide

  122. コンテナの不完全型サポート
    121


    制作・著作
    ━━━━━
    ⓃⒽⓀ

    View Slide