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

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

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

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

4cd53d17fd7e26f611822b508963f613?s=128

Miutsuru kariya

March 28, 2019
Tweet

Transcript

  1. 0

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

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

  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
  5. *this のコピーキャプチャ 4 導入の背景

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

  7. *this のコピーキャプチャ 導入の背景 6 今までの問題点 • デフォルトコピーキャプチャを使うと、さもコピーキャプ チャされてる風に(?)メンバ変数名だけでアクセス可能 になるが、実際には this

    ポインタがコピーされてるだけな ので、メンバ変数は実質参照キャプチャになっている。 • *this をコピーキャプチャするには初期化キャプチャを使 用して別の変数を導入する必要がある。 • デフォルトコピーキャプチャと *this からの初期化キャプ チャを両方使用しても、間違ってメンバ変数名単体でアク セスすると参照アクセスになってしまう。
  8. *this のコピーキャプチャ 導入の背景 7 #include <iostream> 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 経由でのアクセス なので、実質参照キャプチャ
  9. *this のコピーキャプチャ 導入の背景 8 #include <iostream> 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 を導入して、 無理やりコピーキャプチャに。 でもアクセスが面倒…
  10. *this のコピーキャプチャ 導入の背景 9 #include <iostream> 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 経由でアクセスできちゃう…
  11. *this のコピーキャプチャ 10 対応

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

  13. *this のコピーキャプチャ 対応 12 #include <iostream> 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 がコピーキャプチャされる。 アクセスも簡単!
  14. *this のコピーキャプチャ 対応 13 #include <iostream> 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 を導入して、 無理やりコピーキャプチャに。 でもアクセスが面倒… デフォルトコピーキャプチャと一緒に 使っても大丈夫!
  15. *this のコピーキャプチャ 対応 14 #include <iostream> 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 を導入して、 無理やりコピーキャプチャに。 でもアクセスが面倒… もちろん、デフォルト参照キャプチャと 一緒に使っても大丈夫!
  16. *this のコピーキャプチャ 15 悲報

  17. *this のコピーキャプチャ 悲報 16 • デフォルトコピーキャプチャでメンバ変数が実質 参照キャプチャになるのは変わってない。 • C++20 でデフォルトコピーキャプチャで

    this をコ ピーキャプチャする挙動が非推奨になるが、 C++17 ではまだデフォルトコピーキャプチャ指定 時に this を指定できない。
  18. *this のコピーキャプチャ 悲報 17 #include <iostream> 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!!! デフォルトコピーキャプチャだけだと、 今までと何も変わってない…
  19. *this のコピーキャプチャ 悲報 18 #include <iostream> 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 にアクセスするのは非推奨…
  20. *this のコピーキャプチャ 悲報 19 #include <iostream> 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 ではこの書き方はエラー
  21. *this のコピーキャプチャ 悲報 20 結論 デフォルトキャプチャ 使うのは避けよう!

  22. *this のコピーキャプチャ 21 完 終 制作・著作 ━━━━━ ⓃⒽⓀ

  23. emplace の戻り値型変更 22

  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
  25. emplace の戻り値型変更 24 導入の背景

  26. emplace の戻り値型変更 導入の背景 25 emplace_front や emplace_back の直後にその 要素アクセスすることが多い んだが、こいつらの戻り値型

    が void でまんどくさい… 普通の emplace は iterator とか返ってくるのにね…
  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);
  28. emplace の戻り値型変更 27 対応

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

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

    stack::emplace priority_queue::emplace は入らないのね…
  31. emplace の戻り値型変更 対応 30 ペーパーに載ってた例(改) // ① 格納してすぐにメンバ関数呼び出し my_container.emplace_back(…).do_something(…); //

    ② 格納してすぐに関数に引き渡し do_something_else(my_container.emplace_back(…)); // ➂ デフォルト構築してすぐにファイルから読み込み my_container.emplace_back().read(file_stream);
  32. emplace の戻り値型変更 対応 31 push 系はやらないの? ⇓ push するって事は既にオブジェクト持ってる から不要なことが多いし、どうしても格納後オ

    ブジェクトにアクセスしたければ emplace 使 えばいいっしょ(ペーパーより超訳)
  33. emplace の戻り値型変更 対応 32 下記の2点がよくわかりませんでした… • 他の emplace 系の戻り値型は iterator

    な のに何で参照なの? • 何で std::priority_queue::emplace は対象 外なの? 教えて!エロい人!!!
  34. emplace の戻り値型変更 33 完 終 制作・著作 ━━━━━ ⓃⒽⓀ

  35. 単純な文字列変換 34

  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
  37. 単純な文字列変換 36 導入の背景

  38. 単純な文字列変換 導入の背景 37 既存ライブラリの問題点 • 書式指定文字列うぜぇ • 動的メモリ割当強制うぜぇ • ロケールうぜぇ

    • 仮想関数呼び出しうぜぇ • バッファオーバーラン怖ぇ • 入力文字列のエラー分かんねぇのうぜぇ • 入力文字列のスペース勝手に無視すんのうぜぇ • 頭の0x勝手に解釈すんのうぜぇ
  39. 単純な文字列変換 導入の背景 38 既存ライブラリの問題点 結論 うぜぇ ちょっと怖ぇ

  40. 単純な文字列変換 導入の背景 39 既存機能 うぜぇとこ sprintf ロケール、書式指定文字列、バッファオーバーラン snprintf ロケール、書式指定文字列 sscanf

    ロケール、書式指定文字列 atol ロケール、エラー発生不明 strtol ロケール、空白無視、0x勝手に解釈 strstream ロケール、空白無視 stringstream ロケール、空白無視、動的メモリ割当 num_put / num_get facets ロケール、仮想関数呼び出し to_string ロケール、動的メモリ割当 stoi etc. ロケール、動的メモリ割当、空白無視、0x勝手に解釈、 エラー時例外
  41. 単純な文字列変換 導入の背景 40 オレはただ単純に 数値と文字列とを 変換したいだけ なんだ!!!1!

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

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

  44. 単純な文字列変換 対応 43 新規ライブラリの特徴 • 書式指定は文字列じゃない • 動的メモリ割当しない • ロケール無視

    • 仮想関数呼び出ししない • バッファオーバーランしない • 戻り値でエラー返す • 入力文字列のスペース無視しない • 頭の0x解釈しない
  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 任意の浮動小数点型。
  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 と同じ };
  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);
  48. 単純な文字列変換 対応 47 数値から文字列への変換 struct to_chars_result { char* ptr; //

    出力された最後の文字の次へのポインタ errc ec; // 変換失敗した場合のエラーコード };
  49. 単純な文字列変換 対応 48 重要 なんと新規ヘッダ <charconv>

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

  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 で受けてるけど普通は構造化束縛使うよね…
  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{});
  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 は数値として解釈できない文 字(この場合は"+")を指す。
  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 は数値として解釈できない文字を指すので、最 後の数字の次の文字(つまり終端)を指している。 (変換対象の文字の次ではない)
  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{});
  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だけ変換されてる。(わりとワナ)
  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{});
  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{});
  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);
  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{});
  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 は先頭を指すらしい。(たぶん使わない)
  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{});
  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' で終端されるわけではないので注意!
  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"は付かない。(付ける方法は無い) 英文字の出力は小文字。(大文字バージョンは無い)
  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{});
  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 は最後を指すらしい。(たぶん使わない) 変換エラーの場合、バッファの中身は未規定
  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 とは違うので注意。
  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 と違う)
  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 の対応する書式と同じ。 (精度の指定はできるけど幅の指定はできないよ)
  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は付かない。
  71. 単純な文字列変換 70 悲報

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

  73. 単純な文字列変換 悲報 72 何と VC++ 14.16 は 浮動小数点数も それなりに 対応してる!

    すごいぞ VC++! まだ不完全ではあるけど、ちょっと見直した…
  74. 単純な文字列変換 73 完 終 制作・著作 ━━━━━ ⓃⒽⓀ

  75. 検索アルゴリズム 74

  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
  77. 検索アルゴリズム 76 導入の背景

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

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

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

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

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

  83. 検索アルゴリズム 導入の背景 82 template<class ForwardIterator1, class ForwardIterator2> ForwardIterator1 search(ForwardIterator1 first1,

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

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

    タフェースも追加しよう!
  86. 検索アルゴリズム 対応 85 オブジェクト インタフェース ???

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

    実際に検索する
  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';
  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 アルゴリズム
  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'; 検索対象範囲をッ、関数呼び出し演算子の引数に してッ、実際に検索するッ!!! 同じオブジェクトで何度でも検索できるぞッ!!!
  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) がッ、イテレータのペアで返ってくるッ!!! ※ 見つからなかったらどっちも検索対象範囲の最後
  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バイトである事に注意!)
  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バイトである事に注意!) あ、「柿」(かき)はこの文字だけで、あとは「杮」(こけら)です。 見ればわかると思うけど(?)、念のため。
  94. 検索アルゴリズム 93 検索オブジェクトの 種類

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

  96. 検索アルゴリズム 検索オブジェクトの種類 95 デフォルト 愚直に検索。(今までの std::search と同じ※) 前処理しないので、検索パターンや検索対象範囲 が短い場合、検索を1回しかしない場合等ではわり と有利。

    余計なメモリを食わない。 イテレータが前方イテレータでOK。 名前が簡単なのでとても良い。(個人の感想です) ※ std::search と同じと書いたけど、実は規格書には何 も書いてない…
  97. 検索アルゴリズム 検索オブジェクトの種類 96 template<class ForwardIterator1, class BinaryPredicate = equal_to<>> class

    default_searcher { public: default_searcher( ForwardIterator1 pat_first, ForwardIterator1 pat_last, BinaryPredicate pred = BinaryPredicate()); template<class ForwardIterator2> pair<ForwardIterator2, ForwardIterator2> operator()(ForwardIterator2 first, ForwardIterator2 last) const; };
  98. 検索アルゴリズム 検索オブジェクトの種類 97 Boyer-Moore Boyer-Moore法で検索。 ワーストケースがO(n)。(nは検索対象範囲の長さ) 前処理時にテーブルを2つ作るので、前処理時間 がかかるし、結構メモリも食う。 検索パターンや検索対象範囲が長い場合、あるい は、同じ検索パターンで何度も検索する場合には

    有利。 ランダムアクセスイテレータが必要。 名前が難しいので辛い。(個人の(ry
  99. 検索アルゴリズム 検索オブジェクトの種類 98 template<class RandomAccessIterator1, class Hash = hash<typename iterator_traits<RandomAccessIterator1>::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<class RandomAccessIterator2> pair<RandomAccessIterator2, RandomAccessIterator2> operator()(RandomAccessIterator2 first, RandomAccessIterator2 last) const; };
  100. 検索アルゴリズム 検索オブジェクトの種類 99 Boyer-Moore-Horspool Boyer-Moore-Horspool法で検索。 ワーストケースは愚直なのと一緒だが、大抵は O(n)でいける。 前処理時に作るテーブルは1つだけなので、Boyer- Moore法よりは前処理時間もメモリ食わない。 なので、わりとバランスがいいのかな?

    ランダムアクセスイテレータが必要。 名前がとても難しいのでとても辛い。(個人の(ry
  101. 検索アルゴリズム 検索オブジェクトの種類 100 template<class RandomAccessIterator1, class Hash = hash<typename iterator_traits<RandomAccessIterator1>::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<class RandomAccessIterator2> pair<RandomAccessIterator2, RandomAccessIterator2> operator()(RandomAccessIterator2 first, RandomAccessIterator2 last) const; };
  102. 検索アルゴリズム 検索オブジェクトの種類 101 重要 イテレータの参照先はオブ ジェクト作る時と検索する時 で変わったらダメ!!! 変えちゃうと検索が発狂しちゃう…

  103. 検索アルゴリズム 検索オブジェクトの種類 102 重要その2 <algorithm> じゃなくて <functional>

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

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

  106. 検索アルゴリズム 105 完 終 制作・著作 ━━━━━ ⓃⒽⓀ

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

  108. 検索アルゴリズム 107 template<class ForwardIterator, class Searcher> ForwardIterator search(ForwardIterator first, ForwardIterator

    last, const Searcher& searcher); 以下と一緒 return searcher(first, last).first; second 棄てられとる…
  109. 検索アルゴリズム 108 std::search は 要らない子… ※ 実行ポリシー指定できるヤツを除く

  110. 検索アルゴリズム 109 完 終 制作・著作 ━━━━━ ⓃⒽⓀ

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

  112. コンテナの不完全型サポート 111 N3890 Container<Incomplete Type> 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
  113. コンテナの不完全型サポート 112 導入の背景

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

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

  116. コンテナの不完全型サポート 導入の背景 115 こんなの出来たらうれしいよね? by 提案ペーパー struct Entry { std::list<Entry>

    messages; // ここではまだ ... // Entry が不完全型 }; 要は、要素型の定義がまだ不完全な状態でもコンテ ナを使いたい。 それ、Boost.Container で出来るよ
  117. コンテナの不完全型サポート 116 対応

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

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

  120. コンテナの不完全型サポート 対応 119 条件② アロケータが以下を満たす 1. アロケータが完全型 2. 対応する allocator_traits

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

  122. コンテナの不完全型サポート 121 完 終 制作・著作 ━━━━━ ⓃⒽⓀ