├── .textlintrc ├── 000-preface.md ├── 001-sd-6-feature-testing-recommendations.md ├── 002-cpp14-core.md ├── 003-cpp14-core-binary-literals.md ├── 004-cpp14-core-digit-separator.md ├── 005-cpp14-core-deprecated-attribute.md ├── 006-cpp14-core-return-type-deduction-for-normal-function.md ├── 007-cpp14-core-decltype-auto.md ├── 008-cpp14-core-generic-lambda.md ├── 009-cpp14-core-init-lambda-capture.md ├── 010-cpp14-core-variable-template.md ├── 011-cpp14-core-constexpr.md ├── 012-cpp14-core-member-initializer-list-init.md ├── 013-cpp14-core-sized-deallocation.md ├── 014-cpp17-core.md ├── 015-cpp17-core-remove-trigraph.md ├── 016-cpp17-core-hex-float.md ├── 017-cpp17-core-u8-character-literals.md ├── 018-cpp17-core-noexcept-function-type.md ├── 019-cpp17-core-fold-expressions.md ├── 020-cpp17-core-capture-this-by-value.md ├── 021-cpp17-core-constexpr-lambda.md ├── 022-cpp17-core-static-assert.md ├── 023-cpp17-core-nested-namespace-definition.md ├── 024-cpp17-core-fallthrough-attribute.md ├── 025-cpp17-core-nodiscard-attribute.md ├── 026-cpp17-core-maybe_unused-attribute.md ├── 027-cpp17-core-evaluation-order.md ├── 028-cpp17-core-constexpr-if.md ├── 029-cpp17-core-selection-statement-with-initializer.md ├── 030-cpp17-core-deduction-guide.md ├── 031-cpp17-core-template-auto.md ├── 032-cpp17-core-using-attribute-namespace.md ├── 033-cpp17-core-ignore-non-standard-attributes.md ├── 034-cpp17-core-structured-bindings.md ├── 035-cpp17-core-inline-variables.md ├── 036-cpp17-core-using-declaration-pack-expansion.md ├── 037-cpp17-core-std-byte.md ├── 038-cpp17-lib.md ├── 039-cpp17-lib-variant.md ├── 040-cpp17-lib-any.md ├── 041-cpp17-lib-optional.md ├── 042-cpp17-lib-string-view.md ├── 043-cpp17-lib-memory-resource.md ├── 044-cpp17-lib-parallel-algorithm.md ├── 045-cpp17-lib-mathematical-special-functions.md ├── 046-cpp17-lib-misc.md ├── 047-cpp17-lib-misc-hardware-interference-size.md ├── 048-cpp17-misc-uncaught_exceptions.md ├── 049-cpp17-lib-misc-apply.md ├── 050-cpp17-lib-misc-searchers.md ├── 051-cpp17-lib-misc-sample.md ├── 052-cpp17-lib-misc-shared-ptr-for-array.md ├── 053-cpp17-lib-misc-as-const.md ├── 054-cpp17-lib-misc-make-from-tuple.md ├── 055-cpp17-lib-misc-invoke.md ├── 056-cpp17-lib-misc-not-fn.md ├── 057-cpp17-lib-misc-memory.md ├── 058-cpp17-lib-misc-weak-ptr.md ├── 059-cpp17-lib-misc-void-t.md ├── 060-cpp17-lib-misc-bool-constant.md ├── 061-cpp17-lib-misc-traits.md ├── 062-cpp17-lib-misc-minimal-incomplete-type-support-for-containers.md ├── 063-cpp17-lib-misc-emplace.md ├── 064-cpp17-lib-misc-map.md ├── 065-cpp17-lib-misc-node-handle.md ├── 066-cpp17-lib-misc-size.md ├── 067-cpp17-lib-misc-clamp.md ├── 068-cpp17-lib-misc-hypot.md ├── 069-cpp17-lib-misc-atomic-is-always-lock-free.md ├── 070-cpp17-misc-scoped-lock.md ├── 071-cpp17-misc-byte.md ├── 072-cpp17-lib-misc-gcd-lcm.md ├── 073-cpp17-lib-filesystem.md ├── AsciiDWANGO ├── 000-front.tex ├── 000-preface.tex ├── 001-sd-6-feature-testing-recommendations.tex ├── 002-cpp14-core.tex ├── 003-cpp14-core-binary-literals.tex ├── 004-cpp14-core-digit-separator.tex ├── 005-cpp14-core-deprecated-attribute.tex ├── 006-cpp14-core-return-type-deduction-for-normal-function.tex ├── 007-cpp14-core-decltype-auto.tex ├── 008-cpp14-core-generic-lambda.tex ├── 009-cpp14-core-init-lambda-capture.tex ├── 010-cpp14-core-variable-template.tex ├── 011-cpp14-core-constexpr.tex ├── 012-cpp14-core-member-initializer-list-init.tex ├── 013-cpp14-core-sized-deallocation.tex ├── 014-cpp17-core.tex ├── 015-cpp17-core-remove-trigraph.tex ├── 016-cpp17-core-hex-float.tex ├── 017-cpp17-core-u8-character-literals.tex ├── 018-cpp17-core-noexcept-function-type.tex ├── 019-cpp17-core-fold-expressions.tex ├── 020-cpp17-core-capture-this-by-value.tex ├── 021-cpp17-core-constexpr-lambda.tex ├── 022-cpp17-core-static-assert.tex ├── 023-cpp17-core-nested-namespace-definition.tex ├── 024-cpp17-core-fallthrough-attribute.tex ├── 025-cpp17-core-nodiscard-attribute.tex ├── 026-cpp17-core-maybe_unused-attribute.tex ├── 027-cpp17-core-evaluation-order.tex ├── 028-cpp17-core-constexpr-if.tex ├── 029-cpp17-core-selection-statement-with-initializer.tex ├── 030-cpp17-core-deduction-guide.tex ├── 031-cpp17-core-template-auto.tex ├── 032-cpp17-core-using-attribute-namespace.tex ├── 033-cpp17-core-ignore-non-standard-attributes.tex ├── 034-cpp17-core-structured-bindings.tex ├── 035-cpp17-core-inline-variables.tex ├── 036-cpp17-core-using-declaration-pack-expansion.tex ├── 037-cpp17-core-std-byte.tex ├── 038-cpp17-lib.tex ├── 039-cpp17-lib-variant.tex ├── 040-cpp17-lib-any.tex ├── 041-cpp17-lib-optional.tex ├── 042-cpp17-lib-string-view.tex ├── 043-cpp17-lib-memory-resource.tex ├── 044-cpp17-lib-parallel-algorithm.tex ├── 045-cpp17-lib-mathematical-special-functions.tex ├── 046-cpp17-lib-misc.tex ├── 047-cpp17-lib-misc-hardware-interference-size.tex ├── 048-cpp17-misc-uncaught_exceptions.tex ├── 049-cpp17-lib-misc-apply.tex ├── 050-cpp17-lib-misc-searchers.tex ├── 051-cpp17-lib-misc-sample.tex ├── 052-cpp17-lib-misc-shared-ptr-for-array.tex ├── 053-cpp17-lib-misc-as-const.tex ├── 054-cpp17-lib-misc-make-from-tuple.tex ├── 055-cpp17-lib-misc-invoke.tex ├── 056-cpp17-lib-misc-not-fn.tex ├── 057-cpp17-lib-misc-memory.tex ├── 058-cpp17-lib-misc-weak-ptr.tex ├── 059-cpp17-lib-misc-void-t.tex ├── 060-cpp17-lib-misc-bool-constant.tex ├── 061-cpp17-lib-misc-traits.tex ├── 062-cpp17-lib-misc-minimal-incomplete-type-support-for-containers.tex ├── 063-cpp17-lib-misc-emplace.tex ├── 064-cpp17-lib-misc-map.tex ├── 065-cpp17-lib-misc-node-handle.tex ├── 066-cpp17-lib-misc-size.tex ├── 067-cpp17-lib-misc-clamp.tex ├── 068-cpp17-lib-misc-hypot.tex ├── 069-cpp17-lib-misc-atomic-is-always-lock-free.tex ├── 070-cpp17-misc-scoped-lock.tex ├── 071-cpp17-misc-byte.tex ├── 072-cpp17-lib-misc-gcd-lcm.tex ├── 073-cpp17-lib-filesystem.tex ├── asciibook.cls ├── cpp17book.tex ├── cpp17book_1211.pdf ├── fig │ ├── title.eps │ └── tobira.eps ├── indexstyle.ist ├── jsbook.cls └── okuduke.tex ├── LICENSE ├── Makefile ├── README.md ├── bin └── sample-code-checker.cpp ├── docs └── index.html ├── pandoc_title_block └── style.css /.textlintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "preset-ja-technical-writing": { 4 | "no-exclamation-question-mark": false, 5 | "sentence-length": { 6 | "max" : 500 7 | } 8 | } 9 | }, 10 | "filters": { 11 | "comments": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /000-preface.md: -------------------------------------------------------------------------------- 1 | # はじめに 2 | 3 | 本書は2017年に規格制定されたプログラミング言語C++の国際規格、ISO/IEC 14882:2017の新機能をほぼすべて解説している。 4 | 5 | 新しいC++17は不具合を修正し、プログラマーの日々のコーディングを楽にする新機能がいくつも追加された。その結果、C++の特徴であるパフォーマンスや静的型付けは損なうことなく、近年の動的な型の弱い言語に匹敵するほどの柔軟な記述を可能にしている。 6 | 7 | 人によっては、新機能を学ぶのは労多くして益少なしと考えるかもしれぬが、C++の新機能は現実の問題を解決するための便利な道具として追加されるもので、仮に機能を使わないとしても問題はなくならないため、便利な道具なく問題に対処しなければならぬ。また、C++の機能は一般的なプログラマーにとって自然だと感じるように設計されているため、利用は難しくない。もしC++が難しいと感じるのであれば、それはC++が解決すべき現実の問題が難しいのだ。なんとなれば、我々は理想とは程遠い歪なアーキテクチャのコンピューターを扱う時代に生きている。CPUの性能上昇は停滞し、メモリはCPUに比べて遥かに遅く、しかもそのアクセスは定数時間ではない。キャッシュに収まる局所性を持つデータへの操作は無料同然で、キャッシュサイズの単位はすでにMBで数えられている。手のひらに乗る超低電力CPUでさえマルチコアが一般的になり、並列処理、非同期処理は全プログラマーが考慮せねばならぬ問題になった。 8 | 9 | そのような時代にあたっては、かつては最良であった手法はその価値を失い、あるいは逆に悪い手法と成り下がる。同時に昔は現実的ではなかった手法が今ではかえってまともな方法になることさえある。このため、現在活発に使われている生きている言語は、常に時代に合わない機能を廃止し、必要な機能を追加する必要がある。C++の発展はここで留まることなく、今後もC++が使われ続ける限り、修正と機能追加が行われていくだろう。 10 | 11 | 本書の執筆はGithub上で公開して行われた。 12 | 13 | 14 | 15 | 本書のライセンスはGPLv3だ。 16 | 17 | 本書の執筆では株式会社ドワンゴとGitHub上でPull Requestを送ってくれた多くの貢献者の協力によって、誤りを正し、より良い記述を実現できた。この場を借りて謝意を表したい。 18 | 19 | 本書に誤りを見つけたならば、Pull Requestを送る先はだ。 20 | 21 | 江添亮 22 | 23 | # 序 24 | 25 | ## C++の規格 26 | 27 | プログラミング言語C++はISOの傘下で国際規格ISO/IEC 14882として制定されている。この規格は数年おきに改定されている。一般にC++の規格を参照するときは、規格が制定した西暦の下二桁を取って、C++98(1998年発行)とかC++11(2011年発行)と呼ばれている。現在発行されているC++の規格は以下のとおり。 28 | 29 | ### C++98 30 | 31 | C++98は1998年に制定された最初のC++の規格である。本来ならば1994年か1995年には制定させる予定が大幅にずれて、1998年となった。 32 | 33 | ### C++03 34 | 35 | C++03はC++98の文面の曖昧な点を修正したマイナーアップデートとして2003年に制定された。新機能の追加はほとんどない。 36 | 37 | ### C++11 38 | 39 | C++11は制定途中のドラフト段階では元C++0xと呼ばれていた。これは、200x年までに規格が制定される予定だったからだ。予定は大幅に遅れ、ようやく規格が制定されたときにはすでに2011年の年末になっていた。C++11ではとても多くの新機能が追加された。 40 | 41 | ### C++14 42 | 43 | C++14は2014年に制定された。C++11の文面の誤りを修正した他、少し新機能が追加された。本書で解説する。 44 | 45 | ### C++17 46 | 47 | C++17は2017年に制定されることが予定されている最新のC++規格で、本書で解説する。 48 | 49 | ## C++の将来の規格 50 | 51 | ### C++20 52 | 53 | C++20は2020年に制定されることが予定されている次のC++規格だ。この規格では、モジュール、コンセプト、レンジ、ネットワークに注力することが予定されている。 54 | 55 | ## コア言語とライブラリ 56 | 57 | C++の標準規格は、大きく分けて、Cプリプロセッサーとコア言語とライブラリからなる。 58 | 59 | Cプリプロセッサーとは、C++がC言語から受け継いだ機能だ。ソースファイルをトークン列単位で分割して、トークン列の置換ができる。 60 | 61 | コア言語とは、ソースファイルに書かれたトークン列の文法とその意味のことだ。 62 | 63 | ライブラリとは、コア言語機能を使って実装されたもので、標準に提供されているものだ。標準ライブラリには、純粋にコア言語の機能のみで実装できるものと、それ以外の実装依存の方法やコンパイラーマジックが必要なものとがある。 64 | 65 | 66 | -------------------------------------------------------------------------------- /001-sd-6-feature-testing-recommendations.md: -------------------------------------------------------------------------------- 1 | # SD-6 C++のための機能テスト推奨 2 | 3 | C++17には機能テストのためのCプリプロセッサー機能が追加された。 4 | 5 | ## 機能テストマクロ 6 | 7 | 機能テストというのは、C++の実装(C++コンパイラー)が特定の機能をサポートしているかどうかをコンパイル時に判断できる機能だ。本来、C++17の規格に準拠したC++実装は、C++17の機能をすべてサポートしているべきだ。しかし、残念ながら現実のC++コンパイラーの開発はそのようには行われていない。C++17に対応途中のC++コンパイラーは将来的にはすべての機能を実装することを目標としつつも、現時点では一部の機能しか実装していないという状態になる。 8 | 9 | たとえば、C++11で追加された`rvalue`リファレンスという機能に現実のC++コンパイラーが対応しているかどうかをコンパイル時に判定するコードは以下のようになる。 10 | 11 | ~~~cpp 12 | #ifndef __USE_RVALUE_REFERENCES 13 | #if (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 3) || \ 14 | _MSC_VER >= 1600 15 | #if __EDG_VERSION__ > 0 16 | #define __USE_RVALUE_REFERENCES (__EDG_VERSION__ >= 410) 17 | #else 18 | #define __USE_RVALUE_REFERENCES 1 19 | #endif 20 | #elif __clang__ 21 | #define __USE_RVALUE_REFERENCES __has_feature(cxx_rvalue_references) 22 | #else 23 | #define __USE_RVALUE_REFERENCES 0 24 | #endif 25 | #endif 26 | ~~~ 27 | 28 | このそびえ立つクソのようなコードは現実に書かれている。このコードはGCCとMSVCとEDGとClangという現実に使われている主要な4つのC++コンパイラーに対応した`rvalue`リファレンスが実装されているかどうかを判定する機能テストコードだ。 29 | 30 | この複雑なプリプロセッサーを解釈した結果、`__USE_RVALUE_REFERENCES`というプリプロセッサーマクロの値が、もしC++コンパイラーが`rvalue`リファレンスをサポートしているならば1、そうでなければ0となる。後は、このプリプロセッサーマクロで`#if`ガードしたコードを書く。 31 | 32 | ~~~cpp 33 | // 文字列を処理する関数 34 | void process_string( std::string const & str ) ; 35 | 36 | #if __USE_RVALUE_REFERENCES == 1 37 | // 文字列をムーブして処理してよい実装の関数 38 | // C++コンパイラーがrvalueリファレンスを実装していない場合はコンパイルされない 39 | void process_string( std::string && str ) ; 40 | #endif 41 | ~~~ 42 | 43 | C++17では、上のようなそびえ立つクソのようなコードを書かなくてもすむように、標準の機能テストマクロが用意された。C++実装が特定の機能をサポートしている場合、対応する機能テストマクロが定義される。機能テストマクロの値は、その機能がC++標準に採択された年と月を合わせた6桁の整数で表現される。 44 | 45 | たとえば`rvalue`リファレンスの場合、機能テストマクロの名前は`__cpp_rvalue_references`となっている。`rvalue`リファレンスは2006年10月に採択されたので、機能テストマクロの値は200610という値になっている。将来`rvalue`リファレンスの機能が変更されたときは機能テストマクロの値も変更される。この値を調べることによって使っているC++コンパイラーはいつの時代のC++標準の機能をサポートしているか調べることもできる。 46 | 47 | この機能テストマクロを使うと、上のコードの判定は以下のように書ける。 48 | 49 | 50 | ~~~cpp 51 | // 文字列を処理する関数 52 | void process_string( std::string const & str ) ; 53 | 54 | #ifdef __cpp_rvalue_references 55 | // 文字列をムーブして処理してよい実装の関数 56 | // C++コンパイラーがrvalueリファレンスを実装していない場合はコンパイルされない 57 | void process_string( std::string && str ) ; 58 | #endif 59 | ~~~ 60 | 61 | 機能テストマクロの値は通常は気にする必要がない。機能テストマクロが存在するかどうかで機能の有無を確認できるので、通常は`#ifdef`を使えばよい。 62 | 63 | 64 | ## __has_include式 : ヘッダーファイルの存在を判定する 65 | 66 | `__has_include`式は、ヘッダーファイルが存在するかどうかを調べるための機能だ。 67 | 68 | ~~~c++ 69 | __has_include( ヘッダー名 ) 70 | ~~~ 71 | 72 | `__has_include`式はヘッダー名が存在する場合1に、存在しない場合0に置換される。 73 | 74 | 75 | たとえば、C++17の標準ライブラリにはファイルシステムが入る。そのヘッダー名は``だ。C++コンパイラーがファイルシステムライブラリをサポートしているかどうかを調べるには、以下のように書く。 76 | 77 | 78 | ~~~cpp 79 | #if __has_include() 80 | // ファイルシステムをサポートしている 81 | #include 82 | namespace fs = std::filesystem ; 83 | #else 84 | // 実験的な実装を使う 85 | #include 86 | namespace fs = std::experimental::filesystem ; 87 | #endif 88 | ~~~ 89 | 90 | 91 | C++実装が`__has_include`をサポートしているかどうかは、`__has_include`の存在をプリプロセッサーマクロのように`#ifdef`で調べることによって判定できる。 92 | 93 | ~~~cpp 94 | #ifdef __has_include 95 | // __has_includeをサポートしている 96 | #else 97 | // __has_includeをサポートしていない 98 | #endif 99 | ~~~ 100 | 101 | `__has_include`式は`#if`と`#elif`の中でしか使えない。 102 | 103 | ~~~c++ 104 | int main() 105 | { 106 | // エラー 107 | if ( __has_include() ) 108 | { } 109 | } 110 | ~~~ 111 | 112 | ## __has_cpp_attribute式 113 | 114 | C++実装が特定の属性トークンをサポートしているかどうかを調べるには、`__has_cpp_attribute`式が使える。 115 | 116 | ~~~c++ 117 | __has_cpp_attribute( 属性トークン ) 118 | ~~~ 119 | 120 | `__has_cpp_attribute`式は、属性トークンが存在する場合は属性トークンが標準規格に採択された年と月を表す数値に、存在しない場合は0に置換される。 121 | 122 | ~~~cpp 123 | // [[nodiscard]]がサポートされている場合は使う 124 | #if __has_cpp_attribute(nodiscard) 125 | [[nodiscard]] 126 | #endif 127 | void * allocate_memory( std::size_t size ) ; 128 | ~~~ 129 | 130 | `__has_include`式と同じく、`__has_cpp_attribute`式も`#if`か`#elif`の中でしか使えない。`#ifdef`で`__has_cpp_attribute`式の存在の有無を判定できる。 131 | 132 | -------------------------------------------------------------------------------- /002-cpp14-core.md: -------------------------------------------------------------------------------- 1 | # C++14のコア言語の新機能 2 | 3 | C++14で追加された新機能は少ない。C++14はC++03と同じくマイナーアップデートという位置付けで積極的な新機能の追加は見送られたからだ。 4 | -------------------------------------------------------------------------------- /003-cpp14-core-binary-literals.md: -------------------------------------------------------------------------------- 1 | ## 二進数リテラル 2 | 3 | 二進数リテラルは整数リテラルを二進数で記述する機能だ。整数リテラルのプレフィクスに`0B`もしくは`0b`を書くと、二進数リテラルになる。整数を表現する文字は0と1しか使えない。 4 | 5 | ~~~cpp 6 | int main() 7 | { 8 | int x1 = 0b0 ; // 0 9 | int x2 = 0b1 ; // 1 10 | int x3 = 0b10 ; // 2 11 | int x4 = 0b11001100 ; // 204 12 | } 13 | ~~~ 14 | 15 | 二進数リテラルは浮動小数点数リテラルには使えない。 16 | 17 | 機能テストマクロは`__cpp_binary_literals`, 値は201304。 18 | 19 | -------------------------------------------------------------------------------- /004-cpp14-core-digit-separator.md: -------------------------------------------------------------------------------- 1 | ## 数値区切り文字 2 | 3 | 数値区切り文字は、整数リテラルと浮動小数点数リテラルの数値をシングルクオート文字で区切ることができる機能だ。区切り桁は何桁でもよい。 4 | 5 | ~~~cpp 6 | int main() 7 | { 8 | int x1 = 123'456'789 ; 9 | int x2 = 1'2'3'4'5'6'7'8'9 ; 10 | int x3 = 1'2345'6789 ; 11 | int x4 = 1'23'456'789 ; 12 | 13 | double x5 = 3.14159'26535'89793 ; 14 | } 15 | ~~~ 16 | 17 | 大きな数値を扱うとき、ソースファイルに`100000000`と`1000000000`と書かれていた場合、どちらが大きいのか人間の目にはわかりにくい。人間が読んでわかりにくいコードは間違いの元だ。数値区切りを使うと、`100'000'000`と`1'000'000'000`のように書くことができる。これはわかりやすい。 18 | 19 | 他には、1バイト単位で見やすいように区切ることもできる。 20 | 21 | ~~~cpp 22 | int main() 23 | { 24 | unsigned int x1 = 0xde'ad'be'ef ; 25 | unsigned int x2 = 0b11011110'10101101'10111110'11101111 ; 26 | } 27 | ~~~ 28 | 29 | 数値区切りはソースファイルを人間が読みやすくするための機能で、数値に影響を与えない。 30 | -------------------------------------------------------------------------------- /005-cpp14-core-deprecated-attribute.md: -------------------------------------------------------------------------------- 1 | ## [[deprecated]]属性 2 | 3 | `[[deprecated]]`属性は名前とエンティティが、まだ使えるものの利用は推奨されない状態であることを示すのに使える。`[[deprecated]]`属性が指定できる名前とエンティティは、クラス、`typedef`名、変数、非`static`データメンバー、関数、名前空間、`enum`, `enumerator`, テンプレートの特殊化だ。 4 | 5 | それぞれ以下のように指定できる。 6 | 7 | ~~~cpp 8 | // 変数 9 | // どちらでもよい 10 | [[deprecated]] int variable_name1 { } ; 11 | int variable_name2 [[deprecated]] { } ; 12 | 13 | // typedef名 14 | [[deprecated]] typedef int typedef_name1 ; 15 | typedef int typedef_name2 [[deprecated]] ; 16 | using typedef_name3 [[deprecated]] = int ; 17 | 18 | // 関数 19 | // メンバー関数も同じ文法 20 | // どちらでもよい 21 | [[deprecated]] void function_name1() { } 22 | void function_name2 [[deprecated]] () { } 23 | 24 | 25 | // クラス 26 | // unionも同じ 27 | class [[deprecated]] class_name 28 | { 29 | // 非staticデータメンバー 30 | [[deprecated]] int non_static_data_member_name ; 31 | } ; 32 | 33 | // enum 34 | enum class [[deprecated]] enum_name 35 | { 36 | // enumerator 37 | enumerator_name [[deprecated]] = 42 38 | } ; 39 | 40 | 41 | // 名前空間 42 | namespace [[deprecated]] namespace_name { int x ; } 43 | 44 | // テンプレートの特殊化 45 | 46 | template < typename T > 47 | class template_name { } ; 48 | 49 | template < > 50 | class [[deprecated]] template_name { } ; 51 | ~~~ 52 | 53 | `[[deprecated]]`属性が指定された名前やエンティティを使うと、C++コンパイラーは警告メッセージを出す。 54 | 55 | `[[deprecated]]`属性には、文字列を付け加えることができる。これはC++実装によっては警告メッセージに含まれるかもしれない。 56 | 57 | ~~~cpp 58 | [[deprecated("Use of f() is deprecated. Use f(int option) instead.")]] 59 | void f() ; 60 | 61 | void f( int option ) ; 62 | ~~~ 63 | 64 | 機能テストマクロは`__has_cpp_attribute(deprecated)`, 値は201309。 65 | -------------------------------------------------------------------------------- /006-cpp14-core-return-type-deduction-for-normal-function.md: -------------------------------------------------------------------------------- 1 | ## 通常の関数の戻り値の型推定 2 | 3 | 関数の戻り値の型として`auto`を指定すると、戻り値の型を`return`文から推定してくれる。 4 | 5 | ~~~cpp 6 | // int () 7 | auto a(){ return 0 ; } 8 | // double () 9 | auto b(){ return 0.0 ; } 10 | 11 | // T(T) 12 | template < typename T > 13 | auto c(T t){ return t ; } 14 | ~~~ 15 | 16 | `return`文の型が一致していないとエラーとなる。 17 | 18 | ~~~cpp 19 | auto f() 20 | { 21 | return 0 ; // エラー、一致していない 22 | return 0.0 ; // エラー、一致していない 23 | } 24 | ~~~ 25 | 26 | すでに型が決定できる`return`文が存在する場合、関数の戻り値の型を参照するコードも書ける。 27 | 28 | ~~~cpp 29 | auto a() 30 | { 31 | &a ; // エラー、aの戻り値の型が決定していない 32 | return 0 ; 33 | } 34 | 35 | auto b() 36 | { 37 | return 0 ; 38 | &b ; // OK、戻り値の型はint 39 | } 40 | ~~~ 41 | 42 | 関数`a`へのポインターを使うには関数`a`の型が決定していなければならないが、`return`文の前に型は決定できないので関数`a`はエラーになる。関数`b`は`return`文が現れた後なので戻り値の型が決定できる。 43 | 44 | 再帰関数も書ける。 45 | 46 | ~~~cpp 47 | auto sum( unsigned int i ) 48 | { 49 | if ( i == 0 ) 50 | return i ; // 戻り値の型はunsigned int 51 | else 52 | return sum(i-1)+i ; // OK 53 | } 54 | ~~~ 55 | 56 | このコードも、`return`文の順番を逆にすると戻り値の型が決定できずエラーとなるので注意。 57 | 58 | 59 | ~~~cpp 60 | auto sum( unsigned int i ) 61 | { 62 | if ( i != 0 ) 63 | return sum(i-1)+i ; // エラー 64 | else 65 | return i ; 66 | } 67 | ~~~ 68 | 69 | 機能テストマクロは`__cpp_return_type_deduction`, 値は201304。 70 | -------------------------------------------------------------------------------- /007-cpp14-core-decltype-auto.md: -------------------------------------------------------------------------------- 1 | ## decltype(auto) : 厳格なauto 2 | 3 | __警告__:この項目はC++規格の詳細な知識を解説しているため極めて難解になっている。平均的なC++プログラマーはこの知識を得てもよりよいコードが書けるようにはならない。この項目は読み飛ばすべきである。 4 | 5 | `decltype(auto)`は`auto`指定子の代わりに使える厳格な`auto`だ。利用にはC++の規格の厳格な理解が求められる。 6 | 7 | `auto`と`decltype(auto)`は型指定子と呼ばれる文法の一種で、プレイスホルダー型として使う。 8 | 9 | わかりやすく言うと、具体的な型を式から決定する機能だ。 10 | 11 | ~~~cpp 12 | // aはint 13 | auto a = 0 ; 14 | // bはint 15 | auto b() { return 0 ; } 16 | ~~~ 17 | 18 | 変数宣言にプレイスホルダー型を使う場合、型を決定するための式は初期化子と呼ばれる部分に書かれる式を使う。関数の戻り値の型推定にプレイスホルダー型を使う場合、`return`文の式を使う。 19 | 20 | `decltype(auto)`は`auto`の代わりに使うことができる。`decltype(auto)`も型を式から決定する。 21 | 22 | ~~~cpp 23 | // aはint 24 | decltype(auto) a = 0 ; 25 | // bはint 26 | decltype(auto) b() { return 0 ; } 27 | ~~~ 28 | 29 | 一見すると`auto`と`decltype(auto)`は同じようだ。しかし、この2つは式から型を決定する方法が違う。どちらもC++の規格の極めて難しい規則に基づいて決定される。習得には熟練の魔法使いであることが要求される。 30 | 31 | `auto`が式から型を決定するには、`auto`キーワードをテンプレートパラメーター名で置き換えた関数テンプレートの仮引数に、式を実引数として渡してテンプレート実引数推定を行わせた場合に推定される型が使われる。 32 | 33 | たとえば 34 | 35 | ~~~c++ 36 | auto x = 0 ; 37 | ~~~ 38 | 39 | の場合は、 40 | 41 | ~~~c++ 42 | template < typename T > 43 | void f( T u ) ; 44 | ~~~ 45 | 46 | のような関数テンプレートに対して、 47 | 48 | ~~~c++ 49 | f(0) ; 50 | ~~~ 51 | 52 | と実引数を渡したときに`u`の型として推定される型と同じ型になる。 53 | 54 | ~~~c++ 55 | int i ; 56 | auto const * x = &i ; 57 | ~~~ 58 | 59 | の場合には、 60 | 61 | ~~~c++ 62 | template < typename T > 63 | void f( T const * u ) ; 64 | ~~~ 65 | 66 | のような関数テンプレートに 67 | 68 | ~~~c++ 69 | f(&i) ; 70 | ~~~ 71 | 72 | と実引数を渡したときに`u`の型として推定される型と同じ型になる。この場合は`int const *`になる。 73 | 74 | ここまでが`auto`の説明だ。`decltype(auto)`の説明は簡単だ。 75 | 76 | `decltype(auto)`の型は、`auto`を式で置き換えた`decltype`の型になる。 77 | 78 | ~~~c++ 79 | // int 80 | decltype(auto) a = 0 ; 81 | 82 | // int 83 | decltype(auto) f() { return 0 ; } 84 | ~~~ 85 | 86 | 上のコードは、下のコードと同じ意味だ。 87 | 88 | ~~~c++ 89 | decltype(0) a = 0 ; 90 | decltype(0) f() { return 0 ; } 91 | ~~~ 92 | 93 | ここまでは簡単だ。そして、これ以降は黒魔術のようなC++の規格の知識が必要になってくる。 94 | 95 | `auto`と`decltype(auto)`は一見すると同じように見える。型を決定する方法として、`auto`は関数テンプレートの実引数推定を使い、`decltype(auto)`は`decltype`を使う。どちらも式を評価した結果の型になる。いったい何が違うというのか。 96 | 97 | 主な違いは、`auto`は関数呼び出しを使うということだ。関数呼び出しの際にはさまざまな暗黙の型変換が行われる。 98 | 99 | たとえば、配列を関数に渡すと、暗黙の型変換の結果、配列の先頭要素へのポインターになる。 100 | 101 | ~~~cpp 102 | template < typename T > 103 | void f( T u ) {} 104 | 105 | int main() 106 | { 107 | int array[5] ; 108 | // Tはint * 109 | f( array ) ; 110 | } 111 | ~~~ 112 | 113 | では`auto`と`decltype(auto)`を使うとどうなるのか。 114 | 115 | ~~~c++ 116 | int array[5] ; 117 | // int * 118 | auto x1 = array ; 119 | // エラー、配列は配列で初期化できない 120 | decltype(auto) x2 = array ; 121 | ~~~ 122 | 123 | このコードは、以下と同じ意味になる。 124 | 125 | ~~~c++ 126 | int array[5] ; 127 | // int * 128 | int * x1 = array ; 129 | // エラー、配列は配列で初期化できない 130 | int x2[5] = array ; 131 | ~~~ 132 | 133 | `auto`の場合、型は`int *`となる。配列は配列の先頭要素へのポインターへと暗黙に変換できるので、結果のコードは正しい。 134 | 135 | `decltype(auto)`の場合、型は`int [5]`となる。配列は配列で初期化、代入ができないので、このコードはエラーになる。 136 | 137 | 関数型も暗黙の型変換により関数へのポインター型になる。 138 | 139 | ~~~c++ 140 | void f() ; 141 | 142 | // 型はvoid(*)() 143 | auto x1 = f ; 144 | // エラー、関数型は変数にできない 145 | decltype(auto) x2 = f ; 146 | ~~~ 147 | 148 | `auto`はトップレベルのリファレンス修飾子を消すが、`decltype(auto)`は保持する。 149 | 150 | ~~~cpp 151 | int & f() 152 | { 153 | static int x ; 154 | return x ; 155 | } 156 | 157 | int main() 158 | { 159 | // int 160 | auto x1 = f() ; 161 | // int & 162 | decltype(auto) x2 = f() ; 163 | } 164 | ~~~ 165 | 166 | リスト初期化は`auto`では`std::initializer_list`だが、`decltype(auto)`では式ではないためエラー。 167 | 168 | ~~~c++ 169 | int main() 170 | { 171 | // std::initializer_list 172 | auto x1 = { 1,2,3 } ; 173 | // エラー、decltype({1,2,3})はできない 174 | decltype(auto) x2 = { 1,2,3 } ; 175 | } 176 | ~~~ 177 | 178 | `decltype(auto)`は単体で使わなければならない。 179 | 180 | ~~~c++ 181 | // OK 182 | auto const x1 = 0 ; 183 | // エラー 184 | decltype(auto) const x2 = 0 ; 185 | ~~~ 186 | 187 | この他にも`auto`と`decltype(auto)`にはさまざまな違いがある。すべての違いを列挙するのは煩雑なので省略するが、`decltype(auto)`は式の型を直接使う。`auto`はたいていの場合は便利な型の変換が入る。 188 | 189 | `auto`は便利でたいていの場合はうまくいくが暗黙の型の変換が入るため、意図どおりの推定をしてくれないことがある。 190 | 191 | たとえば、引数でリファレンスを受け取り、戻り値でそのリファレンスを返す関数を書くとする。以下のように書くのは間違いだ。 192 | 193 | ~~~cpp 194 | // int ( int & ) 195 | auto f( int & ref ) 196 | { return ref ; } 197 | ~~~ 198 | 199 | なぜならば、戻り値の型は式の型から変化して`int`になってしまうからだ。ここで`decltype(auto)`を使うと、 200 | 201 | ~~~cpp 202 | // int & ( int & ) 203 | decltype(auto) f( int & ref ) 204 | { return ref ; } 205 | ~~~ 206 | 207 | 式の型をそのまま使ってくれる。 208 | 209 | ラムダ式に`decltype(auto)`を使う場合は以下のように書く。 210 | 211 | ~~~c++ 212 | []() -> decltype(auto) { return 0 ; } ; 213 | ~~~ 214 | 215 | `decltype(auto)`は主に関数の戻り値の型推定で式の型をそのまま推定してくれるようにするために追加された機能だ。その利用にはC++の型システムの深い理解が必要になる。 216 | 217 | 機能テストマクロは`__cpp_decltype_auto`, 値は201304。 218 | -------------------------------------------------------------------------------- /008-cpp14-core-generic-lambda.md: -------------------------------------------------------------------------------- 1 | ## ジェネリックラムダ 2 | 3 | ジェネリックラムダはラムダ式の引数の型を書かなくてもすむようにする機能だ。 4 | 5 | 通常のラムダ式は以下のように書く。 6 | 7 | ~~~cpp 8 | int main() 9 | { 10 | []( int i, double d, std::string s ) { } ; 11 | } 12 | ~~~ 13 | 14 | ラムダ式の引数には型が必要だ。しかし、クロージャーオブジェクトの`operator ()`に渡す型はコンパイル時にわかる。コンパイル時にわかるということはわざわざ人間が指定する必要はない。ジェネリックラムダを使えば、引数の型を書くべき場所に`auto`キーワードを書くだけで型を推定してくれる。 15 | 16 | ~~~cpp 17 | int main() 18 | { 19 | []( auto i, auto d, auto s ) { } ; 20 | } 21 | ~~~ 22 | 23 | ジェネリックラムダ式の結果のクロージャー型には呼び出しごとに違う型を渡すことができる。 24 | 25 | ~~~cpp 26 | int main() 27 | { 28 | auto f = []( auto x ) { std::cout << x << '\n' ; } ; 29 | 30 | f( 123 ) ; // int 31 | f( 12.3 ) ; // double 32 | f( "hello" ) ; // char const * 33 | } 34 | ~~~ 35 | 36 | 仕組みは簡単で、以下のようなメンバーテンプレートの`operator ()`を持ったクロージャーオブジェクトが生成されているだけだ。 37 | 38 | ~~~cpp 39 | struct closure_object 40 | { 41 | template < typename T > 42 | auto operator () ( T x ) 43 | { 44 | std::cout << x << '\n' ; 45 | } 46 | } ; 47 | ~~~ 48 | 49 | 機能テストマクロは`__cpp_generic_lambdas`, 値は201304。 50 | -------------------------------------------------------------------------------- /009-cpp14-core-init-lambda-capture.md: -------------------------------------------------------------------------------- 1 | ## 初期化ラムダキャプチャー 2 | 3 | 初期化ラムダキャプチャーはラムダキャプチャーする変数の名前と式を書くことができる機能だ。 4 | 5 | ラムダ式は書かれた場所から見えるスコープの変数をキャプチャーする。 6 | 7 | ~~~cpp 8 | int main() 9 | { 10 | int x = 0 ; 11 | auto f = [=]{ return x ; } ; 12 | f() ; 13 | } 14 | ~~~ 15 | 16 | 初期化ラムダキャプチャーはラムダキャプチャーに初期化子を書くことができる機能だ。 17 | 18 | 19 | ~~~cpp 20 | int main() 21 | { 22 | int x = 0 ; 23 | [ x = x, y = x, &ref = x, x2 = x * 2 ] 24 | {// キャプチャーされた変数を使う 25 | x ; 26 | y ; 27 | ref ; 28 | x2 ; 29 | } ; 30 | } 31 | ~~~~ 32 | 33 | 初期化ラムダキャプチャーは、"識別子 `= expr`" という文法でラムダ導入子`[]`の中に書く。するとあたかも"`auto` 識別子 `= expr ;`"と書いたかのように変数が作られる。これによりキャプチャーする変数の名前を変えたり、まったく新しい変数を宣言することができる。 34 | 35 | 初期化ラムダキャプチャーの識別子の前に`&`を付けると、リファレンスキャプチャー扱いになる。 36 | 37 | ~~~cpp 38 | int main() 39 | { 40 | int x = 0 ; 41 | [ &ref = x ]() 42 | { 43 | ref = 1 ; 44 | }() ; 45 | 46 | // xは1 47 | } 48 | ~~~ 49 | 50 | 51 | 初期化ラムダキャプチャーが追加された理由には変数の名前を変えたりまったく新しい変数を導入したいという目的の他に、非`static`データメンバーをコピーキャプチャーするという目的がある。 52 | 53 | 以下のコードには問題があるが、わかるだろうか。 54 | 55 | ~~~cpp 56 | struct X 57 | { 58 | int data = 42 ; 59 | 60 | auto get_closure_object() 61 | { 62 | return [=]{ return data ; } ; 63 | } 64 | } ; 65 | 66 | 67 | int main() 68 | { 69 | std::function< int() > f ; 70 | 71 | { 72 | X x ; 73 | f = x.get_closure_object() ; 74 | } 75 | 76 | std::cout << f() << std::endl ; 77 | } 78 | ~~~ 79 | 80 | `X::get_closure_object`は`X::data`を返すクロージャーオブジェクトを返す。 81 | 82 | ~~~c++ 83 | auto get_closure_object() 84 | { 85 | return [=]{ return data ; } ; 86 | } 87 | ~~~ 88 | 89 | これを見ると、コピーキャプチャーである`[=]`を使っているので、`data`はクロージャーオブジェクト内にコピーされているように思える。しかし、ラムダ式は非`static`データメンバーをキャプチャーしてはいない。ラムダ式がキャプチャーしているのは`this`ポインターだ。上のコードと下のコードは同じ意味になる。 90 | 91 | ~~~c++ 92 | auto get_closure_object() 93 | { 94 | return [this]{ return this->data ; } ; 95 | } 96 | ~~~ 97 | 98 | さて、`main`関数をもう一度見てみよう。 99 | 100 | ~~~c++ 101 | int main() 102 | { 103 | // クロージャーオブジェクトを代入するための変数 104 | std::function< int() > f ; 105 | 106 | { 107 | X x ; // xが構築される 108 | f = x.get_closure_object() ; 109 | // xが破棄される 110 | } 111 | 112 | // すでにxは破棄された 113 | // return &x->dataで破棄されたxを参照する 114 | std::cout << f() << std::endl ; 115 | } 116 | ~~~ 117 | 118 | なんと、すでに破棄されたオブジェクトへのリファレンスを参照してしまっている。これは未定義の動作だ。 119 | 120 | 初期化ラムダキャプチャーを使えば、非`static`データメンバーもコピーキャプチャーできる。 121 | 122 | ~~~c++ 123 | auto get_closure_object() 124 | { 125 | return [data=data]{ return data ; } ; 126 | } 127 | ~~~ 128 | 129 | なお、ムーブキャプチャーは存在しない。ムーブというのは特殊なコピーなので初期化ラムダキャプチャーがあれば実現できるからだ。 130 | 131 | ~~~cpp 132 | auto f() 133 | { 134 | std::string str ; 135 | std::cin >> str ; 136 | // ムーブ 137 | return [str = std::move(str)]{ return str ; } ; 138 | } 139 | ~~~ 140 | 141 | 機能テストマクロは`__cpp_init_captures`, 値は201304。 142 | -------------------------------------------------------------------------------- /010-cpp14-core-variable-template.md: -------------------------------------------------------------------------------- 1 | ## 変数テンプレート 2 | 3 | 変数テンプレートとは変数宣言をテンプレート宣言にできる機能だ。 4 | 5 | ~~~cpp 6 | template < typename T > 7 | T variable { } ; 8 | 9 | int main() 10 | { 11 | variable = 42 ; 12 | variable = 1.0 ; 13 | } 14 | ~~~ 15 | 16 | これだけではわからないだろうから、順を追って説明する。 17 | 18 | C++ではクラスを宣言できる。 19 | 20 | ~~~cpp 21 | class X 22 | { 23 | int member ; 24 | } ; 25 | ~~~ 26 | 27 | C++ではクラスをテンプレート宣言できる。型テンプレートパラメーターは型として使える。 28 | 29 | 30 | ~~~cpp 31 | template < typename T > 32 | class X 33 | { 34 | public : 35 | T member ; 36 | } ; 37 | 38 | int main() 39 | { 40 | X i ; 41 | i.member = 42 ; // int 42 | 43 | X d ; 44 | d.member = 1.0 ; // double 45 | } 46 | ~~~ 47 | 48 | C++では関数を宣言できる。 49 | 50 | ~~~cpp 51 | int f( int x ) 52 | { return x ; } 53 | ~~~ 54 | 55 | C++では関数をテンプレート宣言できる。型テンプレートパラメーターは型として使える。 56 | 57 | 58 | ~~~cpp 59 | template < typename T > 60 | T f( T x ) 61 | { return x ; } 62 | 63 | int main() 64 | { 65 | auto i = f( 42 ) ; // int 66 | auto d = f( 1.0 ) ; // double 67 | } 68 | ~~~ 69 | 70 | C++11では`typedef`名を宣言するためにエイリアス宣言ができる。 71 | 72 | 73 | ~~~cpp 74 | using type = int ; 75 | ~~~ 76 | 77 | C++11ではエイリアス宣言をテンプレート宣言できる。型テンプレートパラメーターは型として使える。 78 | 79 | ~~~cpp 80 | template < typename T > 81 | using type = T ; 82 | 83 | int main() 84 | { 85 | type i = 42 ; // int 86 | type d = 1.0 ; // double 87 | } 88 | ~~~ 89 | 90 | そろそろパターンが見えてきたのではないだろうか。C++では一部の宣言はテンプレート宣言できるということだ。このパターンを踏まえて以下を考えてみよう。 91 | 92 | 93 | C++では変数を宣言できる。 94 | 95 | ~~~cpp 96 | int variable{} ; 97 | ~~~ 98 | 99 | C++14では変数宣言をテンプレート宣言できる。型テンプレートパラメーターは型として使える。 100 | 101 | ~~~cpp 102 | template < typename T > 103 | T variable { } ; 104 | 105 | int main() 106 | { 107 | variable = 42 ; 108 | variable = 1.0 ; 109 | } 110 | ~~~ 111 | 112 | 113 | 変数テンプレートは名前どおり変数宣言をテンプレート宣言できる機能だ。変数テンプレートはテンプレート宣言なので、名前空間スコープとクラススコープの中にしか書くことができない。 114 | 115 | ~~~cpp 116 | // これはグローバル名前空間スコープという特別な名前空間スコープ 117 | 118 | namespace ns { 119 | // 名前空間スコープ 120 | } 121 | 122 | class 123 | { 124 | // クラススコープ 125 | } ; 126 | ~~~ 127 | 128 | 変数テンプレートの使い道は主に2つある。 129 | 130 | 131 | ### 意味は同じだが型が違う定数 132 | 133 | プログラムでマジックナンバーを変数化しておくのは良い作法であるとされている。たとえば円周率を`3.14...`などと書くよりも`pi`という変数名で扱ったほうがわかりやすい。変数化すると、円周率の値が後で変わったときにプログラムを変更するのも楽になる。 134 | 135 | 136 | ~~~cpp 137 | constexpr double pi = 3.1415926535 ; 138 | ~~~ 139 | 140 | しかし、円周率を表現する型が複数ある場合どうすればいいのか。よくあるのは名前を分ける方法だ。 141 | 142 | ~~~c++ 143 | constexpr float pi_f = 3.1415 ; 144 | constexpr double pi_d = 3.1415926535 ; 145 | constexpr int pi_i = 3 ; 146 | // 任意の精度の実数を表現できるクラスとする 147 | const Real pi_r("3.141592653589793238462643383279") ; 148 | ~~~ 149 | 150 | しかしこれは、使う側で型によって名前を変えなければならない。 151 | 152 | 153 | ~~~c++ 154 | // 円の面積を計算する関数 155 | template < typename T > 156 | T calc_area( T r ) 157 | { 158 | // Tの型によって使うべき名前が変わる 159 | return r * r * ??? ; 160 | } 161 | ~~~ 162 | 163 | 関数テンプレートを使うという手がある。 164 | 165 | 166 | ~~~c++ 167 | template < typename T > 168 | constexpr T pi() 169 | { 170 | return static_cast(3.1415926535) ; 171 | } 172 | 173 | template < > 174 | Real pi() 175 | { 176 | return Real("3.141592653589793238462643383279") ; 177 | } 178 | 179 | 180 | template < typename T > 181 | T calc_area( T r ) 182 | { 183 | return r * r * pi() ; 184 | } 185 | ~~~ 186 | 187 | しかし、この場合引数は何もないのに関数呼び出しのための`()`が必要だ。 188 | 189 | 変数テンプレートを使うと以下のように書ける。 190 | 191 | 192 | ~~~c++ 193 | template < typename T > 194 | constexpr T pi = static_cast(3.1415926535) ; 195 | 196 | template < > 197 | Real pi("3.141592653589793238462643383279") ; 198 | 199 | template < typename T > 200 | T calc_area( T r ) 201 | { 202 | return r * r * pi ; 203 | } 204 | ~~~ 205 | 206 | 207 | ### traitsのラッパー 208 | 209 | 値を返す`traits`で値を得るには`::value`と書かなければならない。 210 | 211 | ~~~cpp 212 | std::is_pointer::value ; 213 | std::is_same< int, int >::value ; 214 | ~~~ 215 | 216 | C++14では`std::integral_constant`に`constexpr operator bool`が追加されたので、以下のようにも書ける。 217 | 218 | ~~~cpp 219 | std::is_pointer{} ; 220 | std::is_same< int, int >{} ; 221 | ~~~ 222 | 223 | しかしまだ面倒だ。変数テンプレートを使うと`traits`の記述が楽になる。 224 | 225 | ~~~c++ 226 | template < typename T > 227 | constexpr bool is_pointer_v = std::is_pointer::value ; 228 | template < typename T, typename U > 229 | constexpr bool is_same_v = std::is_same::value ; 230 | 231 | is_pointer_v ; 232 | is_same_v< int, int > ; 233 | ~~~ 234 | 235 | C++の標準ライブラリでは従来の`traits`ライブラリを変数テンプレートでラップした`_v`版を用意している。 236 | 237 | 機能テストマクロは`__cpp_variable_templates`, 値は201304。 238 | -------------------------------------------------------------------------------- /011-cpp14-core-constexpr.md: -------------------------------------------------------------------------------- 1 | ## constexpr関数の制限緩和 2 | 3 | C++11で追加された`constexpr`関数はとても制限が強い。`constexpr`関数の本体には実質`return`文1つしか書けない。 4 | 5 | C++14では、ほとんど何でも書けるようになった。 6 | 7 | ~~~cpp 8 | constexpr int f( int x ) 9 | { 10 | // 変数を宣言できる 11 | int sum = 0 ; 12 | 13 | // 繰り返し文を書ける 14 | for ( int i = 1 ; i < x ; ++i ) 15 | { 16 | // 変数を変更できる 17 | sum += i ; 18 | } 19 | 20 | return sum ; 21 | } 22 | ~~~ 23 | 24 | 機能テストマクロは`__cpp_constexpr`, 値は201304。 25 | 26 | C++11の`constexpr`関数に対応しているがC++14の`constexpr`関数に対応していないC++実装では、`__cpp_constexpr`マクロの値は200704になる。 27 | -------------------------------------------------------------------------------- /012-cpp14-core-member-initializer-list-init.md: -------------------------------------------------------------------------------- 1 | ## メンバー初期化子とアグリゲート初期化の組み合わせ 2 | 3 | C++14ではメンバー初期化子とアグリゲート初期化が組み合わせられるようになった。 4 | 5 | 6 | メンバー初期化子とはクラスの非`static`データメンバーを`=`で初期化できるC++11の機能だ。 7 | 8 | ~~~cpp 9 | struct S 10 | { 11 | // メンバー初期化子 12 | int data = 123 ; 13 | } ; 14 | ~~~ 15 | 16 | アグリゲート初期化とはアグリゲートの条件を満たす型をリスト初期化で初期化できるC++11の機能だ。 17 | 18 | ~~~cpp 19 | struct S 20 | { 21 | int x, y, z ; 22 | } ; 23 | 24 | S s = { 1,2,3 } ; 25 | // s.x == 1, s.y == 2, s.z == 3 26 | ~~~ 27 | 28 | C++11ではメンバー初期化子を持つクラスはアグリゲート型の条件を満たさないのでアグリゲート初期化ができない。 29 | 30 | C++14では、この制限が緩和された。 31 | 32 | 33 | ~~~cpp 34 | struct S 35 | { 36 | int x, y=1, z ; 37 | } ; 38 | 39 | S s1 = { 1 } ; 40 | // s1.x == 1, s1.y == 1, s1.z == 0 41 | 42 | S s2{ 1,2,3 } ; 43 | // s2.x == 1, s2.y == 2, s2.z == 3 44 | ~~~ 45 | 46 | アグリゲート初期化で、メンバー初期化子を持つ非`static`データメンバーに対応する値がある場合はアグリゲート初期化が優先される。省略された場合はメンバー初期化子で初期化される。アグリゲート初期化でもメンバー初期化子でも明示的に初期化されていない非`static`データメンバーは空の初期化リストで初期化された場合と同じになる。 47 | 48 | 機能テストマクロは`__cpp_aggregate_nsdmi`, 値は201304。 49 | -------------------------------------------------------------------------------- /013-cpp14-core-sized-deallocation.md: -------------------------------------------------------------------------------- 1 | ## サイズ付き解放関数 2 | 3 | C++14では`operator delete`のオーバーロードに、解放すべきストレージのサイズを取得できるオーバーロードが追加された。 4 | 5 | ~~~c++ 6 | void operator delete ( void *, std::size_t ) noexcept ; 7 | void operator delete[] ( void *, std::size_t ) noexcept ; 8 | ~~~ 9 | 10 | 第二引数は`std::size_t`型で、第一引数で指定されたポインターが指す解放すべきストレージのサイズが与えられる。 11 | 12 | 13 | たとえば以下のように使える。 14 | 15 | ~~~cpp 16 | void * operator new ( std::size_t size ) 17 | { 18 | void * ptr = std::malloc( size ) ; 19 | 20 | if ( ptr == nullptr ) 21 | throw std::bad_alloc() ; 22 | 23 | std::cout << "allocated storage of size: " << size << '\n' ; 24 | return ptr ; 25 | } 26 | 27 | void operator delete ( void * ptr, std::size_t size ) noexcept 28 | { 29 | std::cout << "deallocated storage of size: " << size << '\n' ; 30 | std::free( ptr ) ; 31 | } 32 | 33 | int main() 34 | { 35 | auto u1 = std::make_unique(0) ; 36 | auto u2 = std::make_unique(0.0) ; 37 | } 38 | ~~~ 39 | 40 | 機能テストマクロは`__cpp_sized_deallocation`, 値は201309。 41 | -------------------------------------------------------------------------------- /014-cpp17-core.md: -------------------------------------------------------------------------------- 1 | # C++17のコア言語の新機能 2 | 3 | C++14の新機能のおさらいが終わったところで、いよいよC++17のコア言語の新機能を解説していく。 4 | 5 | C++17のコア言語の新機能には、C++11ほどの大きなものはない。 6 | -------------------------------------------------------------------------------- /015-cpp17-core-remove-trigraph.md: -------------------------------------------------------------------------------- 1 | ## トライグラフの廃止 2 | 3 | C++17ではトライグラフが廃止された。 4 | 5 | トライグラフを知らない読者はこの変更を気にする必要はない。トライグラフを知っている読者はなおさら気にする必要はない。 6 | -------------------------------------------------------------------------------- /016-cpp17-core-hex-float.md: -------------------------------------------------------------------------------- 1 | ## 16進数浮動小数点数リテラル 2 | 3 | C++17では浮動小数点数リテラルに16進数を使うことができるようになった。 4 | 5 | 6 | 16進数浮動小数点数リテラルは、プレフィクス`0x`に続いて仮数部を16進数(`0123456789abcdefABCDEF`)で書き、`p`もしくは`P`に続けて指数部を10進数で書く。 7 | 8 | 9 | ~~~cpp 10 | double d1 = 0x1p0 ; // 1 11 | double d2 = 0x1.0p0 ; // 1 12 | double d3 = 0x10p0 ; // 16 13 | double d4 = 0xabcp0 ; // 2748 14 | ~~~ 15 | 16 | 指数部は`e`ではなく`p`か`P`を使う。 17 | 18 | ~~~cpp 19 | double d1 = 0x1p0 ; 20 | double d2 = 0x1P0 ; 21 | ~~~ 22 | 23 | 16進数浮動小数点数リテラルでは、指数部を省略できない。 24 | 25 | ~~~cpp 26 | int a = 0x1 ; // 整数リテラル 27 | 0x1.0 ; // エラー、指数部がない 28 | ~~~ 29 | 30 | 指数部は10進数で記述する。16進数浮動小数点数リテラルは仮数部に2の指数部乗を掛けた値になる。つまり、 31 | 32 | ~~~cpp 33 | 0xNpM 34 | ~~~ 35 | 36 | という浮動小数点数リテラルの値は 37 | 38 | $N \times 2^M$ 39 | 40 | となる。 41 | 42 | ~~~cpp 43 | 0x1p0 ; // 1 44 | 0x1p1 ; // 2 45 | 0x1p2 ; // 4 46 | 0x10p0 ; // 16 47 | 0x10p1 ; // 32 48 | 0x1p-1 ; // 0.5 49 | 0x1p-2 ; // 0.25 50 | ~~~ 51 | 52 | 16進数浮動小数点数リテラルには浮動小数点数サフィックスを記述できる。 53 | 54 | ~~~cpp 55 | auto a = 0x1p0f ; // float 56 | auto b = 0x1p0l ; // long double 57 | ~~~ 58 | 59 | 60 | 16進数浮動小数点数リテラルは、浮動小数点数が表現方法の詳細を知っている環境(たとえばIEEE--754)で、正確な浮動小数点数の表現が記述できるようになる。 61 | 62 | 機能テストマクロは`__cpp_hex_float`, 値は201603。 63 | 64 | -------------------------------------------------------------------------------- /017-cpp17-core-u8-character-literals.md: -------------------------------------------------------------------------------- 1 | ## UTF-8文字リテラル 2 | 3 | C++17ではUTF-8文字リテラルが追加された。 4 | 5 | ~~~cpp 6 | char c = u8'a' ; 7 | ~~~ 8 | 9 | UTF-8文字リテラルは文字リテラルにプレフィクス`u8`を付ける。UTF-8文字リテラルはUTF-8のコード単位1つで表現できる文字を扱うことができる。UCSの規格としては、C0制御文字と基本ラテン文字Unicodeブロックが該当する。UTF-8文字リテラルに書かれた文字が複数のUTF-8コード単位を必要とする場合はエラーとなる。 10 | 11 | ~~~c++ 12 | // エラー 13 | // U+3042はUTF-8は0xE3, 0x81, 0x82という3つのコード単位で表現する必要が 14 | // あるため 15 | u8'あ' ; 16 | ~~~ 17 | 18 | 機能テストマクロはない。 19 | -------------------------------------------------------------------------------- /018-cpp17-core-noexcept-function-type.md: -------------------------------------------------------------------------------- 1 | ## 関数型としての例外指定 2 | 3 | C++17では例外指定が関数型に組み込まれた。 4 | 5 | 例外指定とは`noexcept`のことだ。`noexcept`と`noexcept(true)`が指定された関数は例外を外に投げない。 6 | 7 | C++14ではこの例外指定は型システムに入っていなかった。そのため、無例外指定の付いた関数へのポインター型は型システムで無例外を保証することができなかった。 8 | 9 | ~~~cpp 10 | // C++14のコード 11 | void f() 12 | { 13 | throw 0 ; 14 | } 15 | 16 | int main() 17 | { 18 | // 無例外指定の付いたポインター 19 | void (*p)() noexcept = &f ; 20 | 21 | // 無例外指定があるにもかかわらず例外を投げる 22 | p() ; 23 | } 24 | ~~~ 25 | 26 | C++17では例外指定が型システムに組み込まれた。例外指定のある関数型を例外指定のない関数へのポインター型に変換することはできる。逆はできない。 27 | 28 | ~~~cpp 29 | // 型はvoid() 30 | void f() { } 31 | // 型はvoid() noexcept 32 | void g() noexcept { } 33 | 34 | // OK 35 | // p1, &fは例外指定のない関数へのポインター型 36 | void (*p1)() = &f ; 37 | // OK 38 | // 例外指定のある関数へのポインター型&gを例外指定のない関数へのポインター型p2 39 | // に変換できる 40 | void (*p2)() = &g ; // OK 41 | 42 | // エラー 43 | // 例外指定のない関数へのポインター型&fは例外指定のある関数へのポインター型p3 44 | // に変換できない 45 | void (*p3)() noexcept = &f ; 46 | 47 | // OK 48 | // p4, &gは例外指定のある関数へのポインター型 49 | void (*p4)() noexcept = &g ; 50 | ~~~ 51 | 52 | 機能テストマクロは`__cpp_noexcept_function_type`, 値は201510。 53 | -------------------------------------------------------------------------------- /019-cpp17-core-fold-expressions.md: -------------------------------------------------------------------------------- 1 | ## fold式 2 | 3 | C++17には`fold`式が入った。`fold`は元は数学の概念で畳み込みとも呼ばれている。 4 | 5 | C++における`fold`式とはパラメーターパックの中身に二項演算子を適用するための式だ。 6 | 7 | 今、可変長テンプレートを使って受け取った値をすべて加算した合計を返す関数`sum`を書きたいとする。 8 | 9 | ~~~cpp 10 | template < typename T, typename ... Types > 11 | auto sum( T x, Types ... args ) ; 12 | 13 | int main() 14 | { 15 | int result = sum(1,2,3,4,5,6,7,8,9) ; // 45 16 | } 17 | ~~~ 18 | 19 | このような関数テンプレート`sum`は以下のように実装することができる。 20 | 21 | ~~~cpp 22 | template < typename T > 23 | auto sum( T x ) 24 | { 25 | return x ; 26 | } 27 | 28 | template < typename T, typename ... Types > 29 | auto sum( T x, Types ... args ) 30 | { 31 | return x + sum( args... ) ; 32 | } 33 | ~~~ 34 | 35 | `sum(x, args)`は1番目の引数を`x`で、残りをパラメーターパック`args`で受け取る。そして、`x + sum( args ... )`を返す。すると、`sum( args ... )`はまた`sum(x, args)`に渡されて、1番目の引数、つまり最初から見て2番目の引数が`x`に入り、また`sum`が呼ばれる。このような再帰的な処理を繰り返していく。 36 | 37 | そして、引数が1つだけになると、可変長テンプレートではない`sum`が呼ばれる。これは重要だ。なぜならば可変長テンプレートは0個の引数を取ることができるので、そのまま可変長テンプレート版の`sum`が呼ばれてしまうと、次の`sum`の呼び出しができずにエラーとなる。これを回避するために、また再帰の終了条件のために、引数が1つの`sum`のオーバーロード関数を書いておく。 38 | 39 | 可変長テンプレートでは任意個の引数に対応するために、このような再帰的なコードが必須になる。 40 | 41 | しかし、ここで実現したいこととは$N$個あるパラメーターパック`args`の中身に対して、仮に$N$番目を`args#N`とする表記を使うと、`args#0` + `args#1` + ... + `args#N-1`のような展開をしたいだけだ。C++17の`fold`式はパラメーターパックに対して二項演算子を適用する展開を行う機能だ。 42 | 43 | `fold`式を使うと`sum`は以下のように書ける。 44 | 45 | ~~~cpp 46 | template < typename ... Types > 47 | auto sum( Types ... args ) 48 | { 49 | return ( ... + args ) ; 50 | } 51 | ~~~ 52 | 53 | `( ... + args )`は、`args#0` + `args#1` + ... + `args#N-1`のように展開される。 54 | 55 | `fold`式には、単項`fold`式と二項`fold`式がある。そして、演算子の結合順序に合わせて左`fold`と右`fold`がある。 56 | 57 | `fold`式は必ず括弧で囲まなければならない。 58 | 59 | ~~~cpp 60 | template < typename ... Types > 61 | auto sum( Types ... args ) 62 | { 63 | // fold式 64 | ( ... + args ) ; 65 | // エラー、括弧がない 66 | ... + args ; 67 | } 68 | ~~~ 69 | 70 | 単項`fold`式の文法は以下のいずれかになる。 71 | 72 | 73 | ~~~ 74 | 単項右fold 75 | ( cast-expression fold-operator ... ) 76 | 単項左fold 77 | ( ... fold-operator cast-expression ) 78 | ~~~ 79 | 80 | __例__: 81 | 82 | ~~~cpp 83 | template < typename ... Types > 84 | void f( Types ... args ) 85 | { 86 | // 単項左fold 87 | ( ... + args ) ; 88 | // 単項右fold 89 | ( args + ... ) ; 90 | } 91 | ~~~ 92 | 93 | `cast-expression`には未展開のパラメーターパックが入っていなければならない。 94 | 95 | __例__: 96 | 97 | ~~~c++ 98 | template < typename T > 99 | T f( T x ) { return x ; } 100 | 101 | template < typename ... Types > 102 | auto g( Types ... args ) 103 | { 104 | // f(args#0) + f(args#1) + ... + f(args#N-1) 105 | return ( ... + f(args) ) ; 106 | } 107 | ~~~ 108 | 109 | これは`f(args)`というパターンが展開される。 110 | 111 | `fold-operator`には以下のいずれかの二項演算子を使うことができる。 112 | 113 | 114 | ~~~ 115 | + - * / % ^ & | << >> 116 | += -= *= /= %= ^= &= |= <<= >>= 117 | == != < > <= >= && || , .* ->* 118 | ~~~ 119 | 120 | `fold`式には左`fold`と右`fold`がある。 121 | 122 | 左`fold`式の`( ... op pack )`では、展開結果は`((( pack#0 op pack#1 ) op pack#2 ) ... op pack#N-1 )`となる。右`fold`式の`( pack op ... )`では、展開結果は`( pack#0 op ( pack#1 op ( pack#2 op ( ... op pack#N-1 ))))`となる。 123 | 124 | ~~~cpp 125 | template < typename ... Types > 126 | void sum( Types ... args ) 127 | { 128 | // 左fold 129 | // ((((1+2)+3)+4)+5) 130 | auto left = ( ... + args ) ; 131 | // 右fold 132 | // (1+(2+(3+(4+5)))) 133 | auto right = ( args + ... ) ; 134 | } 135 | 136 | int main() 137 | { 138 | sum(1,2,3,4,5) ; 139 | } 140 | ~~~ 141 | 142 | 浮動小数点数のような交換法則を満たさない型に`fold`式を適用する際には注意が必要だ。 143 | 144 | 145 | 二項`fold`式の文法は以下のいずれかになる。 146 | 147 | ~~~c++ 148 | ( cast-expression fold-operator ... fold-operator cast-expression ) 149 | ~~~ 150 | 151 | 左右の`cast-expression`のどちらか片方だけに未展開のパラメーターパックが入っていなければならない。2つの`fold-operator`は同じ演算子でなければならない。 152 | 153 | 154 | `( e1 op1 ... op2 e2 )`という二項`fold`式があったとき、`e1`にパラメーターパックがある場合は二項右`fold`式、`e2`にパラメーターパックがある場合は二項左`fold`式になる。 155 | 156 | 157 | ~~~cpp 158 | template < typename ... Types > 159 | void sum( Types ... args ) 160 | { 161 | // 左fold 162 | // (((((0+1)+2)+3)+4)+5) 163 | auto left = ( 0 + ... + args ) ; 164 | // 右fold 165 | // (1+(2+(3+(4+(5+0))))) 166 | auto right = ( args + ... + 0 ) ; 167 | } 168 | 169 | int main() 170 | { 171 | sum(1,2,3,4,5) ; 172 | } 173 | ~~~ 174 | 175 | `fold`式はパラメーターパックのそれぞれに二項演算子を適用したいときにわざわざ複雑な再帰的テンプレートを書かずにすむ方法を提供してくれる。 176 | 177 | 機能テストマクロは`__cpp_fold_expressions`, 値は201603。 178 | -------------------------------------------------------------------------------- /020-cpp17-core-capture-this-by-value.md: -------------------------------------------------------------------------------- 1 | ## ラムダ式で\*thisのコピーキャプチャー 2 | 3 | C++17ではラムダ式で`*this`をコピーキャプチャーできるようになった。`*this`をコピーキャプチャーするには、ラムダキャプチャーに`*this`と書く。 4 | 5 | ~~~cpp 6 | struct X 7 | { 8 | int data = 42 ; 9 | auto get() 10 | { 11 | return [*this]() { return this->data ; } ; 12 | } 13 | } ; 14 | 15 | int main() 16 | { 17 | std::function < int () > f ; 18 | { 19 | X x ; 20 | f = x.get() ; 21 | }// xの寿命はここまで 22 | 23 | // コピーされているので問題ない 24 | int data = f() ; 25 | } 26 | ~~~ 27 | 28 | コピーキャプチャーする`*this`はラムダ式が書かれた場所の`*this`だ。 29 | 30 | また、以下のようなコードで挙動の違いを見るとわかりやすい。 31 | 32 | ~~~cpp 33 | struct X 34 | { 35 | int data = 0 ; 36 | void f() 37 | { 38 | // thisはポインターのキャプチャー 39 | // dataはthisポインターをたどる 40 | [this]{ data = 1 ; }() ; 41 | 42 | // this->dataは1 43 | 44 | // エラー、*thisはコピーされている 45 | // クロージャーオブジェクトのコピーキャプチャーされた変数は 46 | // デフォルトで変更できない 47 | [*this]{ data = 2 ; } () ; 48 | 49 | // OK、mutableを使っている 50 | 51 | [*this]() mutable { data = 2 ; } () ; 52 | 53 | // this->dataは1 54 | // 変更されたのはコピーされたクロージャーオブジェクト内の*this 55 | } 56 | } ; 57 | ~~~ 58 | 59 | 最初のラムダ式で生成されるクロージャーオブジェクトは以下のようなものだ。 60 | 61 | ~~~cpp 62 | class closure_object 63 | { 64 | X * this_ptr ; 65 | 66 | public : 67 | closure_object( X * this_ptr ) 68 | : this_ptr(this_ptr) { } 69 | 70 | void operator () () const 71 | { 72 | this_ptr->data = 1 ; 73 | } 74 | } ; 75 | ~~~ 76 | 77 | 2番目のラムダ式では以下のようなクロージャーオブジェクトが生成される。 78 | 79 | ~~~cpp 80 | class closure_object 81 | { 82 | X this_obj ; 83 | X const * this_ptr = &this_obj ; 84 | 85 | public : 86 | closure_object( X const & this_obj ) 87 | : this_obj(this_obj) { } 88 | 89 | void operator () () const 90 | { 91 | this_ptr->data = 2 ; 92 | } 93 | } ; 94 | ~~~ 95 | 96 | これはC++の文法に従っていないのでやや苦しいコード例だが、コピーキャプチャーされた値を変更しようとしているためエラーとなる。 97 | 98 | 3番目のラムダ式では以下のようなクロージャーオブジェクトが生成される。 99 | 100 | ~~~cpp 101 | class closure_object 102 | { 103 | X this_obj ; 104 | X * this_ptr = &this_obj ; 105 | 106 | public : 107 | closure_object( X const & this_obj ) 108 | : this_obj(this_obj) { } 109 | 110 | void operator () () 111 | { 112 | this_ptr->data = 2 ; 113 | } 114 | } ; 115 | ~~~ 116 | 117 | ラムダ式に`mutable`が付いているのでコピーキャプチャーされた値も変更できる。 118 | 119 | `*this`をコピーキャプチャーした場合、`this`キーワードはコピーされたオブジェクトへのポインターになる。 120 | 121 | ~~~cpp 122 | struct X 123 | { 124 | int data = 42 ; 125 | void f() 126 | { 127 | // thisはこのメンバー関数fを呼び出したオブジェクトへのアドレス 128 | std::printf("%p\n", this) ; 129 | 130 | // thisはコピーされた別のオブジェクトへのアドレス 131 | [*this](){ std::printf("%p\n", this) ; }() ; 132 | } 133 | } ; 134 | 135 | int main() 136 | { 137 | X x ; 138 | x.f() ; 139 | } 140 | ~~~ 141 | 142 | この場合、出力される2つのポインターの値は異なる。 143 | 144 | ラムダ式での`*this`のコピーキャプチャーは名前どおり`*this`のコピーキャプチャーを提供する提案だ。同等の機能は初期化キャプチャーでも可能だが、表記が冗長で間違いの元だ。 145 | 146 | ~~~cpp 147 | struct X 148 | { 149 | int data ; 150 | 151 | auto f() 152 | { 153 | return [ tmp = *this ] { return tmp.data ; } ; 154 | } 155 | } ; 156 | ~~~ 157 | 158 | 機能テストマクロは`__cpp_capture_star_this`, 値は201603。 159 | -------------------------------------------------------------------------------- /021-cpp17-core-constexpr-lambda.md: -------------------------------------------------------------------------------- 1 | ## constexprラムダ式 2 | 3 | C++17ではラムダ式が`constexpr`になった。より正確に説明すると、ラムダ式のクロージャーオブジェクトの`operator ()`は条件を満たす場合`constexpr`になる。 4 | 5 | ~~~cpp 6 | int main() 7 | { 8 | auto f = []{ return 42 ; } ; 9 | 10 | constexpr int value = f() ; // OK 11 | } 12 | ~~~ 13 | 14 | `constexpr`の条件を満たすラムダ式はコンパイル時定数を必要とする場所で使うことができる。たとえば`constexpr`変数や配列の添字や`static_assert`などだ。 15 | 16 | ~~~cpp 17 | int main() 18 | { 19 | auto f = []{ return 42 ; } ; 20 | 21 | int a[f()] ; 22 | static_assert( f() == 42 ) ; 23 | std::array b ; 24 | } 25 | ~~~ 26 | 27 | `constexpr`の条件を満たすのであれば、キャプチャーもできる。 28 | 29 | ~~~c++ 30 | int main() 31 | { 32 | int a = 0 ; // 実行時の値 33 | constexpr int b = 0 ; // コンパイル時定数 34 | 35 | auto f = [=]{ return a ; } ; 36 | auto g = [=]{ return b ; } ; 37 | 38 | // エラー、constexprの条件を満たさない 39 | constexpr int c = f() ; 40 | 41 | // OK、constexprの条件を満たす 42 | constexpr int d = g() ; 43 | } 44 | ~~~ 45 | 46 | 以下の内容は上級者向けの解説であり、通常の読者は理解する必要がない。 47 | 48 | `constexpr`ラムダ式はSFINAEの文脈で使うことができない。 49 | 50 | ~~~c++ 51 | // エラー 52 | template < typename T, 53 | bool b = []{ 54 | T t ; 55 | t.func() ; 56 | return true ; 57 | }() ; > 58 | void f() 59 | { 60 | T t ; 61 | t.func() ; 62 | } 63 | ~~~ 64 | 65 | なぜならば、これを許してしまうとテンプレート仮引数に対して任意の式や文がテンプレートのSubstitutionに失敗するかどうかをチェックできてしまうからだ。 66 | 67 | 上級者向けの解説終わり。 68 | 69 | 機能テストマクロは`__cpp_constexpr`, 値は201603。 70 | 71 | `__cpp_constexpr`マクロの値は、C++11の時点で200704、C++14の時点で201304だ。 72 | -------------------------------------------------------------------------------- /022-cpp17-core-static-assert.md: -------------------------------------------------------------------------------- 1 | ## 文字列なしstatic_assert 2 | 3 | C++17では`static_assert`に文字列リテラルを取らないものが追加された。 4 | 5 | 6 | ~~~cpp 7 | static_assert( true ) ; 8 | ~~~ 9 | 10 | C++11で追加された`static_assert`には、文字列リテラルが必須だった。 11 | 12 | ~~~cpp 13 | static_assert( true, "this shall not be asserted." ) ; 14 | ~~~ 15 | 16 | 特に文字列を指定する必要がない場合もあるので、文字列リテラルを取らない`static_assert`が追加された。 17 | 18 | 19 | 機能テストマクロは`__cpp_static_assert`, 値は201411。 20 | 21 | C++11の時点で`__cpp_static_assert`の値は200410。 22 | -------------------------------------------------------------------------------- /023-cpp17-core-nested-namespace-definition.md: -------------------------------------------------------------------------------- 1 | ## ネストされた名前空間定義 2 | 3 | C++17ではネストされた名前空間の定義を楽に書ける。 4 | 5 | ネストされた名前空間とは、`A::B::C`のように名前空間の中に名前空間が入っている名前空間のことだ。 6 | 7 | ~~~cpp 8 | namespace A { 9 | namespace B { 10 | namespace C { 11 | // ... 12 | } 13 | } 14 | } 15 | ~~~ 16 | 17 | C++17では、上記のコードと同じことを以下のように書ける。 18 | 19 | ~~~cpp 20 | namespace A::B::C { 21 | // ... 22 | } 23 | ~~~ 24 | 25 | 26 | 27 | 機能テストマクロは`__cpp_nested_namespace_definitions`, 値は201411。 28 | -------------------------------------------------------------------------------- /024-cpp17-core-fallthrough-attribute.md: -------------------------------------------------------------------------------- 1 | ## [[fallthrough]]属性 2 | 3 | `[[fallthrough]]`属性は`switch`文の中の`case`ラベルを突き抜けるというヒントを出すのに使える。 4 | 5 | `switch`文では対応する`case`ラベルに処理が移る。通常、以下のように書く。 6 | 7 | 8 | ~~~cpp 9 | void f( int x ) 10 | { 11 | switch ( x ) 12 | { 13 | case 0 : 14 | // 処理0 15 | break ; 16 | case 1 : 17 | // 処理1 18 | break ; 19 | case 2 : 20 | // 処理2 21 | break ; 22 | default : 23 | // xがいずれでもない場合の処理 24 | break ; 25 | } 26 | } 27 | ~~~ 28 | 29 | この例を以下のように書くと 30 | 31 | ~~~c++ 32 | case 1 : 33 | // 処理1 34 | case 2 : 35 | // 処理2 36 | break ; 37 | ~~~ 38 | 39 | 40 | `x`が1のときは処理1を実行した後に、処理2も実行される。`switch`文を書くときはこのような誤りを書いてしまうことがある。そのため、賢いC++コンパイラーは`switch`文の`case`ラベルで`break`文や`return`文などで処理が終わらず、次の`case`ラベルや`default`ラベルに処理に突き抜けるコードを発見すると、警告メッセージを出す。 41 | 42 | 43 | しかし、プログラマーの意図がまさに突き抜けて処理してほしい場合、警告メッセージは誤った警告となってしまう。そのような警告メッセージを抑制するため、またコード中に処理が突き抜けるという意図をわかりやすく記述するために、`[[fallthrough]]`属性が追加された。 44 | 45 | ~~~c++ 46 | case 1 : 47 | // 処理1 48 | [[fallthrough]] 49 | case 2 : 50 | // 処理2 51 | break ; 52 | ~~~ 53 | 54 | `[[fallthrough]]`属性を書くと、C++コンパイラーは処理がその先に突き抜けることがわかるので、誤った警告メッセージを抑制できる。また、他人がコードを読むときに意図が明らかになる。 55 | 56 | 57 | 機能テストマクロは`__has_cpp_attribute(fallthrough)`, 値は201603。 58 | -------------------------------------------------------------------------------- /025-cpp17-core-nodiscard-attribute.md: -------------------------------------------------------------------------------- 1 | ## [[nodiscard]]属性 2 | 3 | `[[nodiscard]]`属性は関数の戻り値が無視されてほしくないときに使うことができる。`[[nodiscard]]`属性が付与された関数の戻り値を無視すると警告メッセージが表示される。 4 | 5 | 6 | ~~~cpp 7 | [[nodiscard]] int f() 8 | { 9 | return 0 ; 10 | } 11 | 12 | void g( int ) { } 13 | 14 | int main() 15 | { 16 | // エラー、戻り値が無視されている 17 | f() ; 18 | 19 | // OK、戻り値は無視されていない 20 | int result = f() ; 21 | g( f() ) ; 22 | f() + 1 ; 23 | (void) f() ; 24 | } 25 | ~~~ 26 | 27 | 戻り値を無視する、というのは万能ではない。上の例でも、意味的には戻り値は無視されていると言えるが、コンパイラーはこの場合に戻り値が無視されているとは考えない。 28 | 29 | `[[nodiscard]]`の目的は、戻り値を無視してほしくない関数をユーザーが利用したときの初歩的な間違いを防ぐためにある。`void`型にキャストするような意図的な戻り値の無視まで防ぐようには作られていない。 30 | 31 | 32 | `[[nodiscard]]`属性を使うべき関数は、戻り値を無視してほしくない関数だ。どのような関数が戻り値を無視してほしくないかというと大きく2つある。 33 | 34 | 35 | 戻り値をエラーなどのユーザーが確認しなければならない情報の通知に使う関数。 36 | 37 | ~~~c++ 38 | enum struct error_code 39 | { 40 | no_error, some_operations_failed, serious_error 41 | } ; 42 | 43 | // 失敗するかもしれない処理 44 | error_code do_something_that_may_fail() 45 | { 46 | // 処理 47 | 48 | if ( is_error_condition() ) 49 | return error_code::serious_error ; 50 | 51 | // 処理 52 | 53 | return error_code::no_error ; 54 | } 55 | 56 | // エラーがいっさい発生しなかったときの処理 57 | int do_something_on_no_error() ; 58 | 59 | int main() 60 | { 61 | // エラーを確認していない 62 | do_something_that_may_fail() ; 63 | 64 | // エラーがない前提で次の処理をしようとする 65 | do_something_on_no_error() ; 66 | } 67 | ~~~ 68 | 69 | 70 | 関数に`[[nodiscard]]`属性を付与しておけば、このようなユーザー側の初歩的なエラー確認の欠如に警告メッセージを出せる。 71 | 72 | `[[nodiscard]]`属性は、クラスと`enum`にも付与することができる。 73 | 74 | ~~~cpp 75 | class [[nodiscard]] X { } ; 76 | enum class [[nodiscard]] Y { } ; 77 | ~~~ 78 | 79 | `[[nodiscard]]`が付与されたクラスか`enum`が戻り値の型である関数は`[[nodiscard]]`が付与された扱いとなる。 80 | 81 | ~~~cpp 82 | class [[nodiscard]] X { } ; 83 | 84 | X f() { return X{} ; } 85 | 86 | int main() 87 | { 88 | // 警告、戻り値が無視されている 89 | f() ; 90 | } 91 | ~~~ 92 | 93 | 機能テストマクロは`__has_cpp_attribute(nodiscard)`, 値は201603。 94 | -------------------------------------------------------------------------------- /026-cpp17-core-maybe_unused-attribute.md: -------------------------------------------------------------------------------- 1 | ## [[maybe_unused]]属性 2 | 3 | `[[maybe_unused]]`属性は名前やエンティティが意図的に使われないことを示すのに使える。 4 | 5 | 現実のC++のコードでは、宣言されているのにソースコードだけを考慮するとどこからも使われていないように見える名前やエンティティが存在する。 6 | 7 | ~~~cpp 8 | void do_something( int *, int * ) ; 9 | 10 | void f() 11 | { 12 | int x[5] ; 13 | char reserved[1024] = { } ; 14 | int y[5] ; 15 | 16 | do_something( x, y ) ; 17 | } 18 | ~~~ 19 | 20 | ここでは`reserved`という名前はどこからも使われていない。一見すると不必要な名前に見える。優秀なC++コンパイラーはこのようなどこからも使われていない名前に対して「どこからも使われていない」という警告メッセージを出す。 21 | 22 | しかし、コンパイラーから見えているソースコードがプログラムのすべてではない。さまざまな理由で`reserved`のような一見使われていない変数が必要になる。 23 | 24 | 25 | たとえば、`reserved`はスタック破壊を検出するための領域かもしれない。プログラムはC++以外の言語で書かれたコードとリンクしていて、そこで使われるのかもしれない。あるいはOSや外部デバイスが読み書きするメモリーとして確保しているのかもしれない。 26 | 27 | どのような理由にせよ、名前やエンティティが一見使われていないように見えるが存在が必要であるという意味を表すのに、`[[maybe_unused]]`属性を使うことができる。これにより、C++コンパイラーの「未使用の名前」という警告メッセージを抑制できる。 28 | 29 | 30 | ~~~cpp 31 | [[maybe_unused]] char reserved[1024] ; 32 | ~~~ 33 | 34 | `[[maybe_unused]]`属性を適用できる名前とエンティティの宣言は、クラス、`typedef`名、変数、非`static`データメンバー、関数、`enum`, `enumerator`だ。 35 | 36 | 37 | ~~~cpp 38 | // クラス 39 | class [[maybe_unused]] class_name 40 | { 41 | // 非staticデータメンバー 42 | [[maybe_unused]] int non_static_data_member ; 43 | 44 | } ; 45 | 46 | // typedef名 47 | // どちらでもよい 48 | [[maybe_unused]] typedef int typedef_name1 ; 49 | typedef int typedef_name2 [[maybe_unused]] ; 50 | 51 | // エイリアス宣言によるtypedef名 52 | using typedef_name3 [[maybe_unused]] = int ; 53 | 54 | // 変数 55 | // どちらでもよい 56 | [[maybe_unused]] int variable_name1{}; 57 | int variable_name2 [[maybe_unused]] { } ; 58 | 59 | // 関数 60 | // メンバー関数も同じ文法 61 | // どちらでもよい 62 | [[maybe_unused]] void function_name1() { } 63 | void function_name2 [[maybe_unused]] () { } 64 | 65 | enum [[maybe_unused]] enum_name 66 | { 67 | // enumerator 68 | enumerator_name [[maybe_unused]] = 0 69 | } ; 70 | ~~~ 71 | 72 | 機能テストマクロは`__has_cpp_attribute(maybe_unused)`, 値は201603 73 | -------------------------------------------------------------------------------- /027-cpp17-core-evaluation-order.md: -------------------------------------------------------------------------------- 1 | ## 演算子のオペランドの評価順序の固定 2 | 3 | C++17では演算子のオペランドの評価順序が固定された。 4 | 5 | 以下の式は、`a`, `b`の順番に評価されることが規格上保証される。`@=`の`@`には文法上許される任意の演算子が入る(`+=`, `-=`など)。 6 | 7 | ~~~c++ 8 | a.b 9 | a->b 10 | a->*b 11 | a(b1,b2,b3) 12 | b = a 13 | b @= a 14 | a[b] 15 | a << b 16 | a >> b 17 | ~~~ 18 | 19 | つまり、 20 | 21 | ~~~cpp 22 | int* f() ; 23 | int g() ; 24 | 25 | int main() 26 | { 27 | f()[g()] ; 28 | } 29 | ~~~ 30 | 31 | と書いた場合、関数`f`がまず先に呼び出されて、次に関数`g`が呼び出されることが保証される。 32 | 33 | 関数呼び出しの実引数のオペランド`b1`, `b2`, `b3`の評価順序は未規定のままだ。 34 | 35 | これにより、既存の未定義の動作となっていたコードの挙動が定まる。 36 | -------------------------------------------------------------------------------- /029-cpp17-core-selection-statement-with-initializer.md: -------------------------------------------------------------------------------- 1 | ## 初期化文付き条件文 2 | 3 | C++17では、条件文に初期化文を記述できるようになった。 4 | 5 | 6 | ~~~c++ 7 | if ( int x = 1 ; x ) 8 | /*...*/ ; 9 | 10 | switch( int x = 1 ; x ) 11 | { 12 | case 1 : 13 | /*... */; 14 | } 15 | ~~~ 16 | 17 | これは、以下のコードと同じ意味になる。 18 | 19 | ~~~c++ 20 | { 21 | int x = 1 ; 22 | if ( x ) ; 23 | } 24 | 25 | { 26 | int x = 1 ; 27 | switch( x ) 28 | { 29 | case 1 : ; 30 | } 31 | } 32 | ~~~ 33 | 34 | なぜこのような機能が追加されたかというと、変数を宣言し、`if`文の条件に変数を使い、`if`文を実行後は変数を使用しない、というパターンは現実のコードで頻出するからだ。 35 | 36 | ~~~c++ 37 | void * ptr = std::malloc(10) ; 38 | if ( ptr != nullptr ) 39 | { 40 | // 処理 41 | std::free(ptr) ; 42 | } 43 | // これ以降ptrは使わない 44 | 45 | FILE * file = std::fopen("text.txt", "r") ; 46 | if ( file != nullptr ) 47 | { 48 | // 処理 49 | std::fclose( file ) ; 50 | } 51 | // これ以降fileは使わない 52 | 53 | auto int_ptr = std::make_unique(42) ; 54 | if ( int_ptr ) 55 | { 56 | // 処理 57 | } 58 | // これ以降int_ptrは使わない 59 | ~~~ 60 | 61 | 62 | 上記のコードには問題がある。これ以降変数は使わないが、変数自体は使えるからだ。 63 | 64 | ~~~c++ 65 | auto ptr = std::make_unique(42) ; 66 | if ( ptr ) 67 | { 68 | // 処理 69 | } 70 | // これ以降ptrは使わない 71 | 72 | // でも使える 73 | int value = *ptr ; 74 | ~~~ 75 | 76 | 変数を使えないようにするには、ブロックスコープで囲むことで、変数をスコープから外してやればよい。 77 | 78 | ~~~c++ 79 | { 80 | auto int_ptr = std::make_unique(42) ; 81 | if ( ptr ) 82 | { 83 | // 処理 84 | } 85 | // ptrは破棄される 86 | } 87 | // これ以降ptrは使わないし使えない 88 | ~~~ 89 | 90 | このようなパターンは頻出するので、初期化文付きの条件文が追加された。 91 | 92 | ~~~c++ 93 | if ( auto ptr = std::make_unique(42) ; ptr ) 94 | { 95 | // 処理 96 | } 97 | ~~~ 98 | 99 | 100 | -------------------------------------------------------------------------------- /030-cpp17-core-deduction-guide.md: -------------------------------------------------------------------------------- 1 | ## クラステンプレートのコンストラクターからの実引数推定 2 | 3 | C++17ではクラステンプレートのコンストラクターの実引数からテンプレート実引数の推定が行えるようになった。 4 | 5 | ~~~cpp 6 | template < typename T > 7 | struct X 8 | { 9 | X( T t ) { } 10 | } ; 11 | 12 | int main() 13 | { 14 | X x1(0) ; // X 15 | X x2(0.0) ; // X 16 | X x3("hello") ; // X 17 | } 18 | ~~~ 19 | 20 | これは関数テンプレートが実引数からテンプレート実引数の推定が行えるのと同じだ。 21 | 22 | ~~~cpp 23 | template < typename T > 24 | void f( T t ) { } 25 | 26 | int main() 27 | { 28 | f( 0 ) ; // f 29 | f( 0.0 ) ; // f 30 | f( "hello" ) ; // f 31 | } 32 | ~~~ 33 | 34 | 35 | 36 | ### 推定ガイド 37 | 38 | クラステンプレートのコンストラクターからの実引数は便利だが、クラスのコンストラクターはクラステンプレートのテンプレートパラメーターに一致しない場合もある。そのような場合はそのままでは実引数推定ができない。 39 | 40 | ~~~cpp 41 | // コンテナー風のクラス 42 | template < typename T > 43 | class Container 44 | { 45 | std::vector c ; 46 | public : 47 | // 初期化にイテレーターのペアを取る 48 | // IteratorはTではない 49 | // Tは推定できない 50 | template < typename Iterator > 51 | Container( Iterator first, Iterator last ) 52 | : c( first, last ) 53 | { } 54 | } ; 55 | 56 | 57 | int main() 58 | { 59 | int a[] = { 1,2,3,4,5 } ; 60 | 61 | // エラー 62 | // Tを推定できない 63 | Container c( std::begin(a), std::end(a) ) ; 64 | } 65 | ~~~ 66 | 67 | このため、C++17には推定ガイドという機能が提供されている。 68 | 69 | ~~~c++ 70 | テンプレート名( 引数リスト ) -> テンプレートid ; 71 | ~~~ 72 | 73 | これを使うと、以下のように書ける。 74 | 75 | ~~~c++ 76 | template < typename Iterator > 77 | Container( Iterator, Iterator ) 78 | -> Container< typename std::iterator_traits< Iterator >::value_type > ; 79 | ~~~ 80 | 81 | C++コンパイラーはこの推定ガイドを使って、`Container::Container(Iterator, Iterator)`からは、`T`を`std::iterator_traits::value_type`として推定すればいいのだと判断できる。 82 | 83 | たとえば、初期化リストに対応するには以下のように書く。 84 | 85 | ~~~cpp 86 | template < typename T > 87 | class Container 88 | { 89 | std::vector c ; 90 | public : 91 | 92 | Container( std::initializer_list init ) 93 | : c( init ) 94 | { } 95 | } ; 96 | 97 | 98 | template < typename T > 99 | Container( std::initializer_list ) -> Container ; 100 | 101 | 102 | int main() 103 | { 104 | Container c = { 1,2,3,4,5 } ; 105 | } 106 | ~~~ 107 | 108 | C++コンパイラーはこの推定ガイドから、`Container::Container( std::initializer_list )`の場合は`T`を`T`として推定すればよいことがわかる。 109 | 110 | 機能テストマクロは`__cpp_deduction_guides`, 値は201606。 111 | -------------------------------------------------------------------------------- /031-cpp17-core-template-auto.md: -------------------------------------------------------------------------------- 1 | ## autoによる非型テンプレートパラメーターの宣言 2 | 3 | C++17では非型テンプレートパラメーターの宣言に`auto`を使うことができるようになった。 4 | 5 | ~~~cpp 6 | template < auto x > 7 | struct X { } ; 8 | 9 | void f() { } 10 | 11 | int main() 12 | { 13 | X<0> x1 ; 14 | X<0l> x2 ; 15 | X<&f> x3 ; 16 | } 17 | ~~~ 18 | 19 | これはC++14までであれば、以下のように書かなければならなかった。 20 | 21 | ~~~cpp 22 | template < typename T, T x > 23 | struct X { } ; 24 | 25 | void f() { } 26 | 27 | int main() 28 | { 29 | X x1 ; 30 | X x2 ; 31 | X x3 ; 32 | } 33 | ~~~ 34 | 35 | 機能テストマクロは`__cpp_template_auto`, 値は201606。 36 | -------------------------------------------------------------------------------- /032-cpp17-core-using-attribute-namespace.md: -------------------------------------------------------------------------------- 1 | ## using属性名前空間 2 | 3 | C++17では、属性名前空間に`using`ディレクティブのような記述ができるようになった。 4 | 5 | ~~~c++ 6 | 7 | // [[extension::foo, extension::bar]]と同じ 8 | [[ using extension : foo, bar ]] int x ; 9 | ~~~ 10 | 11 | 属性トークンには、属性名前空間を付けることができる。これにより、独自拡張の属性トークンの名前の衝突を避けることができる。 12 | 13 | たとえば、あるC++コンパイラーには独自拡張として`foo`, `bar`という属性トークンがあり、別のC++コンパイラーも同じく独自拡張として`foo`, `bar`という属性トークンを持っているが、それぞれ意味が違っている場合、コードの意味も違ってしまう。 14 | 15 | ~~~c++ 16 | [[ foo, bar ]] int x ; 17 | ~~~ 18 | 19 | このため、C++には属性名前空間という文法が用意されている。注意深いC++コンパイラーは独自拡張の属性トークンには属性名前空間を設定していることだろう。 20 | 21 | ~~~c++ 22 | [[ extension::foo, extension::bar ]] int x ; 23 | ~~~ 24 | 25 | 問題は、これをいちいち記述するのは面倒だということだ。 26 | 27 | C++17では、`using`属性名前空間という機能により、`using`ディレクティブのような名前空間の省略が可能になった。文法は`using`ディレクティブと似ていて、属性の中で`using name : ...`と書くことで、コロンに続く属性トークンに、属性名前空間`name`を付けたものと同じ効果が得られる。 28 | 29 | -------------------------------------------------------------------------------- /033-cpp17-core-ignore-non-standard-attributes.md: -------------------------------------------------------------------------------- 1 | ## 非標準属性の無視 2 | 3 | C++17では、非標準の属性トークンは無視される。 4 | 5 | ~~~cpp 6 | // OK、無視される 7 | [[ wefapiaofeaofjaopfij ]] int x ; 8 | ~~~ 9 | 10 | 属性はC++コンパイラーによる独自拡張をC++の規格に準拠する形で穏便に追加するための機能だ。その属性のためにコンパイルエラーになった場合、けっきょくCプリプロセッサーを使うか、わずらわしさから独自の文法が使われてしまう。そのためこの機能は必須だ。 11 | -------------------------------------------------------------------------------- /035-cpp17-core-inline-variables.md: -------------------------------------------------------------------------------- 1 | ## inline変数 2 | 3 | C++17では変数に`inline`キーワードを指定できるようになった。 4 | 5 | ~~~cpp 6 | inline int variable ; 7 | ~~~ 8 | 9 | このような変数を`inline`変数と呼ぶ。その意味は`inline`関数と同じだ。 10 | 11 | ### inlineの歴史的な意味 12 | 13 | 今は昔、本書執筆から30年以上は昔に、`inline`キーワードがC++に追加された。 14 | 15 | `inline`の現在の意味は誤解されている。 16 | 17 | `inline`関数の意味は、「関数を強制的にインライン展開させるための機能」**ではない**。 18 | 19 | 大事なことなのでもう一度書くが、`inline`関数の意味は、「関数を強制的にインライン展開させるための機能」**ではない**。 20 | 21 | 確かに、かつて`inline`関数の意味は、関数を強制的にインライン展開させるための機能だった。 22 | 23 | 関数のインライン展開とは、たとえば以下のようなコードがあったとき、 24 | 25 | ~~~cpp 26 | int min( int a, int b ) 27 | { return a < b ? a : b ; } 28 | 29 | int main() 30 | { 31 | int a, b ; 32 | std::cin >> a >> b ; 33 | 34 | // aとbのうち小さい方を選ぶ 35 | int value = min( a, b ) ; 36 | } 37 | ~~~ 38 | 39 | この関数`min`は十分に小さく、関数呼び出しのコストは無視できないオーバーヘッドになるため、以下のような最適化が考えられる。 40 | 41 | ~~~cpp 42 | int main() 43 | { 44 | int a, b ; 45 | std::cin >> a >> b ; 46 | 47 | int value = a < b ? a : b ; 48 | } 49 | ~~~ 50 | 51 | このように関数の中身を展開することを、関数のインライン展開という。 52 | 53 | 人間が関数のインライン展開を手で行うのは面倒だ。それにコードが読みにくい。"`min(a,b)`"と"`a 30 | struct S : Types ... 31 | { 32 | using Types::operator() ... ; 33 | void operator () ( long ) { } 34 | } ; 35 | 36 | 37 | struct A 38 | { 39 | void operator () ( int ) { } 40 | } ; 41 | 42 | struct B 43 | { 44 | void operator () ( double ) { } 45 | } ; 46 | 47 | int main() 48 | { 49 | S s ; 50 | s(0) ; // A::operator() 51 | s(0L) ; // S::operator() 52 | s(0.0) ; // B::operator() 53 | } 54 | ~~~ 55 | 56 | 機能テストマクロは`__cpp_variadic_using`, 値は201611。 57 | -------------------------------------------------------------------------------- /037-cpp17-core-std-byte.md: -------------------------------------------------------------------------------- 1 | ## std::byte : バイトを表現する型 {#std.byte} 2 | 3 | C++17では、バイトを表現する型が入った。ライブラリでもあるのだがコア言語で特別な型として扱われている。 4 | 5 | バイトとはC++のメモリーモデルにおけるストレージの単位で、C++においてユニークなアドレスが付与される最小単位だ。C++の規格はいまだに1バイトが具体的に何ビットであるのかを規定していない。これは過去にバイトのサイズが8ビットではないアーキテクチャーが存在したためだ。 6 | 7 | バイトのビット数は``で定義されているプリプロセッサーマクロ、`CHAR_BIT`で知ることができる。 8 | 9 | C++17では、1バイトはUTF-8の8ビットの1コード単位をすべて表現できると規定している。 10 | 11 | `std::byte`型は、生のバイト列を表すための型として使うことができる。生の1バイトを表すには`unsigned char`型が慣習的に使われてきたが、`std::byte`型は生の1バイトを表現する型として、新たにC++17で追加された。複数バイトが連続するストレージは、`unsigned char`の配列型、もしくは`std::byte`の配列型として表現できる。 12 | 13 | `std::byte`型は、``で以下のように定義されている。 14 | 15 | ~~~c++ 16 | namespace std 17 | { 18 | enum class byte : unsigned char { } ; 19 | } 20 | ~~~ 21 | 22 | `std::byte`はライブラリとして`scoped enum`型で定義されている。これにより、他の整数型からの暗黙の型変換が行えない。 23 | 24 | 値`0x12`の`std::byte`型の変数は以下のように定義できる。 25 | 26 | ~~~cpp 27 | int main() 28 | { 29 | std::byte b{0x12} ; 30 | } 31 | ~~~ 32 | 33 | `std::byte`型の値がほしい場合は、以下のように書くことができる。 34 | 35 | ~~~cpp 36 | int main() 37 | { 38 | std::byte b{} ; 39 | 40 | b = std::byte( 1 ) ; 41 | b = std::byte{ 1 } ; 42 | b = static_cast< std::byte >( 1 ) ; 43 | b = static_cast< std::byte >( 0b11110000 ) ; 44 | } 45 | ~~~ 46 | 47 | `std::byte`型は他の数値型からは暗黙に型変換できない。これによりうっかりと型を取り違えてバイト型と他の型を演算してしまうことを防ぐことができる。 48 | 49 | ~~~c++ 50 | int main() 51 | { 52 | // エラー、()による初期化はint型からの暗黙の変換が入る 53 | std::byte b1(1) ; 54 | 55 | // エラー、=による初期化はint型からの暗黙の変換が入る 56 | std::byte b2 = 1 ; 57 | 58 | std::byte b{} ; 59 | 60 | // エラー、operator =によるint型の代入は暗黙の変換が入る 61 | b = 1 ; 62 | // エラー、operator =によるdouble型の代入は暗黙の変換が入る 63 | b = 1.0 ; 64 | } 65 | ~~~ 66 | 67 | `std::byte`型は`{}`によって初期化するが、縮小変換を禁止するルールにより、`std::byte`型が表現できる値の範囲でなければエラーとなる。 68 | 69 | たとえば、今`std::byte`が8ビットで、最小値が0、最大値が255の環境だとする。 70 | 71 | ~~~cpp 72 | int main() 73 | { 74 | // エラー、表現できる値の範囲ではない 75 | std::byte b1{-1} ; 76 | // エラー、表現できる値の範囲ではない 77 | std::byte b2{256} ; 78 | } 79 | ~~~ 80 | 81 | `std::byte`は内部のストレージをバイト単位でアクセスできるようにするため、規格上`char`と同じような配慮が行われている。 82 | 83 | ~~~cpp 84 | int main() 85 | { 86 | int x = 42 ; 87 | 88 | std::byte * rep = reinterpret_cast< std::byte * >(&x) ; 89 | } 90 | ~~~ 91 | 92 | `std::byte`は一部の演算子がオーバーロードされているので、通常の整数型のように使うことができる。ただし、バイトをビット列演算するのに使う一部の演算子だけだ。 93 | 94 | 具体的には、以下に示すシフト、ビットOR, ビット列AND, ビット列XOR, ビット列NOTだ。 95 | 96 | ~~~ 97 | <<= << 98 | >>= >> 99 | |= | 100 | &= & 101 | ^= ^ 102 | ~ 103 | ~~~ 104 | 105 | 四則演算などの演算子はサポートしていない。 106 | 107 | `std::byteはstd::to_integer(std::byte)`により、`IntType`型の整数型に変換できる。 108 | 109 | ~~~cpp 110 | int main() 111 | { 112 | std::byte b{42} ; 113 | 114 | // int型の値は42 115 | auto i = std::to_integer(b) ; 116 | } 117 | ~~~ 118 | -------------------------------------------------------------------------------- /038-cpp17-lib.md: -------------------------------------------------------------------------------- 1 | # C++17の型安全な値を格納するライブラリ 2 | 3 | C++17では型安全に値を格納するライブラリとして、`variant`, `any`, `optional`が追加された。 4 | -------------------------------------------------------------------------------- /040-cpp17-lib-any.md: -------------------------------------------------------------------------------- 1 | ## any : どんな型の値でも保持できるクラス 2 | 3 | ### 使い方 4 | 5 | ヘッダーファイル``で定義されている`std::any`は、ほとんどどんな型の値でも保持できるクラスだ。 6 | 7 | ~~~cpp 8 | #include 9 | 10 | int main() 11 | { 12 | std::any a ; 13 | 14 | a = 0 ; // int 15 | a = 1.0 ; // double 16 | a = "hello" ; // char const * 17 | 18 | std::vector v ; 19 | a = v ; // std::vector 20 | 21 | // 保持しているstd::vectorのコピー 22 | auto value = std::any_cast< std::vector >( a ) ; 23 | } 24 | ~~~ 25 | 26 | `any`が保持できない型は、コピー構築できない型だ。 27 | 28 | ### anyの構築と破棄 29 | 30 | クラス`any`はテンプレートではない。そのため宣言は単純だ。 31 | 32 | ~~~cpp 33 | int main() 34 | { 35 | // 値を保持しない 36 | std::any a ; 37 | // int型の値を保持する 38 | std::any b( 0 ) ; 39 | // double型の値を保持する 40 | std::any c( 0.0 ) ; 41 | } 42 | ~~~ 43 | 44 | `any`が保持する型を事前に指定する必要はない。 45 | 46 | クラス`any`を破棄すると、そのとき保持していた値が適切に破棄される。 47 | 48 | ### in_place_typeコンストラクター 49 | 50 | `any`のコンストラクターで`emplace`をするために`in_place_type`が使える。 51 | 52 | 53 | ~~~cpp 54 | struct X 55 | { 56 | X( int, int ) { } 57 | } ; 58 | 59 | int main() 60 | { 61 | // 型XをX(1, 2)で構築した結果の値を保持する 62 | std::any a( std::in_place_type, 1, 2 ) ; 63 | } 64 | ~~~ 65 | 66 | ### anyへの代入 67 | 68 | `any`への代入も普通のプログラマーの期待どおりの動きをする。 69 | 70 | 71 | ~~~cpp 72 | int main() 73 | { 74 | std::any a ; 75 | std::any b ; 76 | 77 | // aはint型の値42を保持する 78 | a = 42 ; 79 | // bはint型の値42を保持する 80 | b = a ; 81 | 82 | } 83 | ~~~ 84 | 85 | ### anyのメンバー関数 86 | 87 | #### emplace 88 | 89 | ~~~c++ 90 | template 91 | decay_t& emplace(Args&&... args); 92 | ~~~ 93 | 94 | 95 | `any`は`emplace`メンバー関数をサポートしている。 96 | 97 | 98 | 99 | ~~~cpp 100 | struct X 101 | { 102 | X( int, int ) { } 103 | } ; 104 | 105 | int main() 106 | { 107 | std::any a ; 108 | 109 | // 型XをX(1, 2)で構築した結果の値を保持する 110 | a.emplace( 1, 2 ) ; 111 | } 112 | ~~~ 113 | 114 | 115 | #### reset : 値の破棄 116 | 117 | ~~~c++ 118 | void reset() noexcept ; 119 | ~~~ 120 | 121 | `any`の`reset`メンバー関数は、`any`の保持してある値を破棄する。`reset`を呼び出した後の`any`は値を保持しない。 122 | 123 | 124 | ~~~cpp 125 | int main() 126 | { 127 | // aは値を保持しない 128 | std::any a ; 129 | // aはint型の値を保持する 130 | a = 0 ; 131 | 132 | // aは値を保持しない 133 | a.reset() ; 134 | } 135 | ~~~ 136 | 137 | #### swap : スワップ 138 | 139 | `any`は`swap`メンバー関数をサポートしている。 140 | 141 | ~~~cpp 142 | int main() 143 | { 144 | std::any a(0) ; 145 | std::any b(0.0) ; 146 | 147 | // aはint型の値を保持 148 | // bはdouble型の値を保持 149 | 150 | a.swap(b) ; 151 | 152 | // aはdouble型の値を保持 153 | // bはint型の値を保持 154 | } 155 | ~~~ 156 | 157 | #### has_value : 値を保持しているかどうか調べる 158 | 159 | ~~~c++ 160 | bool has_value() const noexcept; 161 | ~~~ 162 | 163 | `any`の`has_value`メンバー関数は`any`が値を保持しているかどうかを調べる。値を保持しているならば`true`を、保持していないならば`false`を返す。 164 | 165 | ~~~cpp 166 | int main() 167 | { 168 | std::any a ; 169 | 170 | // false 171 | bool b1 = a.has_value() ; 172 | 173 | a = 0 ; 174 | // true 175 | bool b2 = a.has_value() ; 176 | 177 | a.reset() ; 178 | // false 179 | bool b3 = a.has_value() ; 180 | } 181 | ~~~ 182 | 183 | #### type : 保持している型のtype_infoを得る 184 | 185 | ~~~c++ 186 | const type_info& type() const noexcept; 187 | ~~~ 188 | 189 | `type`メンバー関数は、保持している型`T`の`typeid(T)`を返す。値を保持していない場合、`typeid(void)`を返す。 190 | 191 | ~~~cpp 192 | int main() 193 | { 194 | std::any a ; 195 | 196 | // typeid(void) 197 | auto & t1 = a.type() ; 198 | 199 | a = 0 ; 200 | // typeid(int) 201 | auto & t2 = a.type() ; 202 | 203 | a = 0.0 ; 204 | // typeid(double) 205 | auto & t3 = a.type() ; 206 | } 207 | ~~~ 208 | 209 | ### anyのフリー関数 210 | 211 | #### make_any\ : T型のanyを作る 212 | 213 | ~~~c++ 214 | template 215 | any make_any(Args&& ...args); 216 | 217 | template 218 | any make_any(initializer_list il, Args&& ...args); 219 | ~~~ 220 | 221 | 222 | `make_any( args... )`は`T`型をコンストラクター実引数`args...`で構築した値を保持する`any`を返す。 223 | 224 | ~~~cpp 225 | struct X 226 | { 227 | X( int, int ) { } 228 | } ; 229 | 230 | int main() 231 | { 232 | // int型の値を保持するany 233 | auto a = std::make_any( 0 ) ; 234 | // double型の値を保持するany 235 | auto b = std::make_any( 0.0 ) ; 236 | 237 | // X型の値を保持するany 238 | auto c = std::make_any( 1, 2 ) ; 239 | } 240 | ~~~ 241 | 242 | #### any_cast : 保持している値の取り出し 243 | 244 | ~~~c++ 245 | template T any_cast(const any& operand); 246 | template T any_cast(any& operand); 247 | template T any_cast(any&& operand); 248 | ~~~ 249 | 250 | `any_cast(operand)`は`operand`が保持している値を返す。 251 | 252 | ~~~cpp 253 | int main() 254 | { 255 | std::any a(0) ; 256 | 257 | int value = std::any_cast(a) ; 258 | } 259 | ~~~ 260 | 261 | `any_cast`で指定した`T`型が、`any`が保持している型ではない場合、`std::bad_any_cast`が`throw`される。 262 | 263 | ~~~cpp 264 | int main() 265 | { 266 | try { 267 | std::any a ; 268 | std::any_cast(a) ; 269 | } catch( std::bad_any_cast e ) 270 | { 271 | // 型を保持していなかった 272 | } 273 | 274 | } 275 | ~~~ 276 | 277 | ~~~c++ 278 | template 279 | const T* any_cast(const any* operand) noexcept; 280 | template 281 | T* any_cast(any* operand) noexcept; 282 | ~~~ 283 | 284 | `any_cast`に`any`へのポインターを渡すと、`T`へのポインター型が返される。`any`が`T`型を保持している場合は`T`型を参照するポインターが返る。保持していない場合は、`nullptr`が返る。 285 | 286 | ~~~cpp 287 | int main() 288 | { 289 | std::any a(42) ; 290 | 291 | // int型の値を参照するポインター 292 | int * p1 = std::any_cast( &a ) ; 293 | 294 | // nullptr 295 | double * p2 = std::any_cast( &a ) ; 296 | } 297 | ~~~ 298 | 299 | 300 | -------------------------------------------------------------------------------- /046-cpp17-lib-misc.md: -------------------------------------------------------------------------------- 1 | # その他の標準ライブラリ 2 | 3 | この章ではC++17で追加された細かいライブラリをまとめて解説する。 4 | -------------------------------------------------------------------------------- /047-cpp17-lib-misc-hardware-interference-size.md: -------------------------------------------------------------------------------- 1 | ## ハードウェア干渉サイズ(キャッシュライン) 2 | 3 | C++17にはハードウェアの干渉サイズを取得するライブラリが入った。ハードウェアの干渉サイズとは、俗にキャッシュライン(cache line)とも呼ばれている概念だ。 4 | 5 | 残念ながら、この2017年では、メモリーは極めて遅い。そのため、プロセッサーはより高速にアクセスできるキャッシュメモリーを用意している。メモリーに対するキャッシュはある程度のまとまったバイト数単位で行われる。この単位が何バイトであるのかは実装依存だ。C++17にはこのサイズを取得できるライブラリが入った。 6 | 7 | ハードウェア干渉サイズを知りたい理由は2つある。2つのオブジェクトを同一の局所性を持つキャッシュに載せたくない場合と載せたい場合だ。 8 | 9 | 2つのオブジェクトのうち、一方は頻繁に変更し、もう一方はめったに変更しない場合で、2つのオブジェクトが同じ局所性を持つキャッシュに載っている場合、よく変更するオブジェクトを変更しただけで、めったに変更しないオブジェクトも、メモリーとの同期が発生する。 10 | 11 | ~~~cpp 12 | struct Data 13 | { 14 | int counter ; 15 | int status ; 16 | } ; 17 | ~~~ 18 | 19 | ここで、`counter`は頻繁に変更するが、`status`はめったに変更しない場合、`counter`と`status`の間に適切なパディングを挿入することで、2つのオブジェクトが同じ局所性を持たないようにしたい。 20 | 21 | この場合には、`std::hardware_destructive_interference_size`が使える。 22 | 23 | ~~~cpp 24 | struct Data 25 | { 26 | int counter ; 27 | std::byte padding[ 28 | std::hardware_destructive_interference_size - sizeof(int) 29 | ] ; 30 | int status ; 31 | } ; 32 | ~~~ 33 | 34 | 反対に、2つのオブジェクトを同一の局所性を持つキャッシュに載せたい場合、`std::hardware_constructive_interference_size`が使える。 35 | 36 | 37 | 38 | ハードウェア干渉サイズは``ヘッダーで以下のように定義されている。 39 | 40 | ~~~c++ 41 | namespace std { 42 | inline constexpr size_t 43 | hardware_destructive_interference_size = 実装依存 ; 44 | inline constexpr size_t 45 | hardware_constructive_interference_size = 実装依存 ; 46 | } 47 | ~~~ 48 | 49 | -------------------------------------------------------------------------------- /048-cpp17-misc-uncaught_exceptions.md: -------------------------------------------------------------------------------- 1 | ## std::uncaught_exceptions 2 | 3 | C++14までは、まだ`catch`されていない例外がある場合は、`bool std::uncaught_exception()`で判定することができた。 4 | 5 | ~~~c++ 6 | struct X 7 | { 8 | ~X() 9 | { 10 | if ( std::uncaught_exception() ) 11 | { 12 | // デストラクターはスタックアンワインディング中に呼ばれた 13 | } 14 | else 15 | { 16 | // 通常の破棄 17 | } 18 | } 19 | } ; 20 | 21 | int main() 22 | { 23 | { 24 | X x ; 25 | }// 通常の破棄 26 | 27 | { 28 | X x ; 29 | throw 0 ; 30 | }// スタックアンワインディング中 31 | 32 | } 33 | ~~~ 34 | 35 | `bool std::uncaught_exception()`は、C++17では非推奨扱いになった。いずれ廃止される見込みだ。 36 | 37 | 廃止の理由としては、単に以下のような例で役に立たないからだ。 38 | 39 | ~~~c++ 40 | struct X 41 | { 42 | ~X() 43 | { 44 | try { 45 | // true 46 | bool b = std::uncaught_exception() ; 47 | } catch( ... ) { } 48 | } 49 | } ; 50 | ~~~ 51 | 52 | このため、`int std::uncaught_exceptions()`が新たに追加された。この関数は現在`catch`されていない例外の個数を返す。 53 | 54 | ~~~c++ 55 | struct X 56 | { 57 | ~X() 58 | { 59 | try { 60 | if ( int x = std::uncaught_exceptions() ; x > 1 ) 61 | { 62 | // ネストされた例外 63 | } 64 | } catch( ... ) 65 | } 66 | 67 | } ; 68 | ~~~ 69 | -------------------------------------------------------------------------------- /049-cpp17-lib-misc-apply.md: -------------------------------------------------------------------------------- 1 | ## apply : tupleの要素を実引数に関数を呼び出す 2 | 3 | ~~~c++ 4 | template 5 | constexpr decltype(auto) apply(F&& f, Tuple&& t); 6 | ~~~ 7 | 8 | `std::apply`は`tuple`のそれぞれの要素を順番に実引数に渡して関数を呼び出すヘルパー関数だ。 9 | 10 | ある要素数`N`の`tuple t`と関数オブジェクト`f`に対して、`apply( f, t )`は、`f( get<0>(t), get<1>(t), ... , get(t) )`のように`f`を関数呼び出しする。 11 | 12 | __例__: 13 | 14 | ~~~cpp 15 | template < typename ... Types > 16 | void f( Types ... args ) { } 17 | 18 | int main() 19 | { 20 | // int, int, int 21 | std::tuple t1( 1,2,3 ) ; 22 | 23 | // f( 1, 2, 3 )の関数呼び出し 24 | std::apply( f, t1 ) ; 25 | 26 | // int, double, const char * 27 | std::tuple t2( 123, 4.56, "hello" ) ; 28 | 29 | // f( 123, 4.56, "hello" )の関数呼び出し 30 | std::apply( f, t2 ) ; 31 | } 32 | ~~~ 33 | -------------------------------------------------------------------------------- /050-cpp17-lib-misc-searchers.md: -------------------------------------------------------------------------------- 1 | ## Searcher : 検索 2 | 3 | C++17では``に`searcher`というライブラリが追加された。これは順序のあるオブジェクトの集合に、ある部分集合(パターン)が含まれているかどうかを検索するためのライブラリだ。その最も一般的な応用例は文字列検索となる。 4 | 5 | `searcher`の基本的な設計としては、クラスのオブジェクトを構築して、コンストラクターで検索したい部分集合(パターン)を与え、`operator ()`で部分集合が含まれているかを検索したい集合を与える。 6 | 7 | この設計のライブラリが追加された理由は、パターンの検索のために何らかの事前の準備を状態として保持しておきたい検索アルゴリズムを実装するためだ。 8 | 9 | ### default_searcher 10 | 11 | クラス`std::default_searcher`は以下のように宣言されている。 12 | 13 | ~~~c++ 14 | template < class ForwardIterator1, 15 | class BinaryPredicate = equal_to<> > 16 | class default_searcher { 17 | public: 18 | // コンストラクター 19 | default_searcher( 20 | ForwardIterator1 pat_first, ForwardIterator1 pat_last 21 | , BinaryPredicate pred = BinaryPredicate() ) ; 22 | 23 | // operator () 24 | template 25 | pair 26 | operator()(ForwardIterator2 first, ForwardIterator2 last) const ; 27 | } ; 28 | ~~~ 29 | 30 | コンストラクターで部分集合を受け取る。`operator ()`で集合を受け取り、部分集合(パターン)と一致した場所をイテレーターのペアで返す。見つからない場合、イテレーターのペアは`[last, last)`になっている。 31 | 32 | 以下のように使う。 33 | 34 | ~~~c++ 35 | int main() 36 | { 37 | std::string pattern("fox") ; 38 | std::default_searcher 39 | fox_searcher( std::begin(pattern), std::end(pattern) ) ; 40 | 41 | std::string corpus = "The quick brown fox jumps over the lazy dog" ; 42 | 43 | auto[first, last] = fox_searcher( std::begin(corpus), 44 | std::end(corpus) ) ; 45 | std::string fox( first, last ) ; 46 | } 47 | ~~~ 48 | 49 | `default_searcher`の検索は、内部的に`std::search`が使われる。 50 | 51 | ### boyer_moore_searcher 52 | 53 | `std::boyer_moore_searcher`はBoyer-Moore文字列検索アルゴリズムを使って部分集合の検索を行う。 54 | 55 | Boyer-Moore文字列検索アルゴリズムは極めて効率的な文字列検索のアルゴリズムだ。Boyer-MooreアルゴリズムはBob BoyerとStrother Mooreによって発明され、1977年のCommunications of the ACMで発表された。その内容は以下のURLで読むことができる。 56 | 57 | 58 | 59 | 愚直に実装した文字列検索アルゴリズムは検索すべき部分文字列(パターン)を検索対象の文字列(コーパス)から探す際、パターンの先頭の文字をコーパスの先頭から順に探していき、見つかれば2文字目以降も一致するかどうかを調べる。 60 | 61 | Boyer-Mooreアルゴリズムはパターンの末尾の文字から調べる。文字が一致しなければ、パターンから絶対に不一致であるとわかっている長さだけの文字を比較せずに読み飛ばす。これによって効率的な文字列検索を実現している。 62 | 63 | Boyer-Mooreアルゴリズムは事前にパターンのどの文字が不一致ならば何文字比較せずに読み飛ばせるかという情報を計算した2つのテーブルを生成する必要がある。このため、Boyer-Mooreアルゴリズムはメモリー使用量と検索前の準備時間というコストがかかる。そのコストは、より効率的な検索により相殺できる。特に、パターンが長い場合は効果的だ。 64 | 65 | C++17に入るBoyer-Mooreアルゴリズムに基づく検索は、テンプレートを使った汎用的な`char`型のような状態数の少ない型に対しての実装だけではなく、ハッシュを使ったハッシュマップのようなデータ構造を使うことにより、任意の型に対応できる汎用的な設計になっている。 66 | 67 | クラス`boyer_moore_searcher`は以下のように宣言されている。 68 | 69 | ~~~c++ 70 | template < 71 | class RandomAccessIterator1, 72 | class Hash = hash< 73 | typename iterator_traits::value_type>, 74 | class BinaryPredicate = equal_to<> > 75 | class boyer_moore_searcher { 76 | public: 77 | // コンストラクター 78 | boyer_moore_searcher( 79 | RandomAccessIterator1 pat_first, 80 | RandomAccessIterator1 pat_last, 81 | Hash hf = Hash(), 82 | BinaryPredicate pred = BinaryPredicate() ) ; 83 | 84 | // operator () 85 | template 86 | pair 87 | operator()( RandomAccessIterator2 first, 88 | RandomAccessIterator2 last) const; 89 | } ; 90 | ~~~ 91 | 92 | `boyer_moore_searcher`は、文字列以外にも適用できる汎用的な設計のため、ハッシュ関数を取る。`char`型のような取りうる状態数の少ない型以外が渡された場合は、`std::unordered_map`のようなメモリー使用量を削減できる何らかのデータ構造を使ってテーブルを構築する。 93 | 94 | 使い方は`default_searcher`とほとんど変わらない。 95 | 96 | 97 | ~~~c++ 98 | int main() 99 | { 100 | std::string pattern("fox") ; 101 | std::boyer_moore_searcher 102 | fox_searcher( std::begin(pattern), std::end(pattern) ) ; 103 | 104 | std::string corpus = "The quick brown fox jumps over the lazy dog" ; 105 | 106 | auto[first, last] = fox_searcher( std::begin(corpus), 107 | std::end(corpus) ) ; 108 | std::string fox( first, last ) ; 109 | } 110 | ~~~ 111 | 112 | 113 | ### boyer_moore_horspool_searcher 114 | 115 | `std::boyer_moore_horspool_searcher`はBoyer-Moore-Horspool検索アルゴリズムを使って部分集合の検索を行う。Boyer-Moore-HorspoolアルゴリズムはNigel Horspoolによって1980年に発表された。 116 | 117 | __参考__:"Practical fast searching in strings" 1980 118 | 119 | Boyer-Moore-Horspoolアルゴリズムは内部テーブルに使うメモリー使用量を削減しているが、最悪計算量の点でオリジナルのBoyer-Mooreアルゴリズムには劣っている。つまり、実行時間の増大を犠牲にしてメモリー使用量を削減したトレードオフなアルゴリズムと言える。 120 | 121 | クラス`boyer_moore_horspool_searcher`の宣言は以下のとおり。 122 | 123 | ~~~c++ 124 | template < 125 | class RandomAccessIterator1, 126 | class Hash = hash< 127 | typename iterator_traits::value_type>, 128 | class BinaryPredicate = equal_to<> > 129 | class boyer_moore_horspool_searcher { 130 | public: 131 | // コンストラクター 132 | boyer_moore_horspool_searcher( 133 | RandomAccessIterator1 pat_first, 134 | RandomAccessIterator1 pat_last, 135 | Hash hf = Hash(), 136 | BinaryPredicate pred = BinaryPredicate() ); 137 | 138 | // operator () 139 | template 140 | pair 141 | operator()( RandomAccessIterator2 first, 142 | RandomAccessIterator2 last) const; 143 | } ; 144 | ~~~ 145 | 146 | 使い方は`boyer_moore_searcher`と変わらない。 147 | 148 | 149 | 150 | 151 | ~~~c++ 152 | int main() 153 | { 154 | std::string pattern("fox") ; 155 | std::boyer_moore_horspool_searcher 156 | fox_searcher( std::begin(pattern), std::end(pattern) ) ; 157 | 158 | std::string corpus = "The quick brown fox jumps over the lazy dog" ; 159 | 160 | auto[first, last] = fox_searcher( std::begin(corpus), 161 | std::end(corpus) ) ; 162 | std::string fox( first, last ) ; 163 | } 164 | ~~~ 165 | -------------------------------------------------------------------------------- /052-cpp17-lib-misc-shared-ptr-for-array.md: -------------------------------------------------------------------------------- 1 | ## shared_ptr\ : 配列に対するshared_ptr 2 | 3 | C++17では、`shared_ptr`が配列に対応した。 4 | 5 | ~~~cpp 6 | int main() 7 | { 8 | // 配列対応のshared_ptr 9 | std::shared_ptr< int [] > ptr( new int[5] ) ; 10 | 11 | // operator []で配列に添字アクセスできる 12 | ptr[0] = 42 ; 13 | 14 | // shared_ptrのデストラクターがdelete[]を呼び出す 15 | } 16 | ~~~ 17 | -------------------------------------------------------------------------------- /053-cpp17-lib-misc-as-const.md: -------------------------------------------------------------------------------- 1 | ## as_const: const性の付与 2 | 3 | `as_const`はヘッダーファイル``で定義されている。 4 | 5 | ~~~c++ 6 | template constexpr add_const_t& as_const(T& t) noexcept 7 | { 8 | return t ; 9 | } 10 | ~~~ 11 | 12 | `as_const`は引数として渡した`lvalue`リファレンスを`const`な`lvalue`リファレンスにキャストする関数だ。`const`性を付与する手軽なヘルパー関数として使うことができる。 13 | 14 | ~~~cpp 15 | // 1 16 | template < typename T > 17 | void f( T & ) {} 18 | // 2、こちらを呼び出したい 19 | template < typename T > 20 | void f( T const & ) { } 21 | 22 | int main() 23 | { 24 | int x{} ; 25 | 26 | f(x) ; // 1 27 | 28 | // constを付与する冗長な方法 29 | int const & ref = x ; 30 | f(ref) ; // 2 31 | 32 | // 簡潔 33 | f( std::as_const(x) ) ; // 2 34 | } 35 | ~~~ 36 | -------------------------------------------------------------------------------- /054-cpp17-lib-misc-make-from-tuple.md: -------------------------------------------------------------------------------- 1 | ## make_from_tuple : tupleの要素を実引数にコンストラクターを呼び出す 2 | 3 | `make_from_tuple`はヘッダーファイル``で定義されている。 4 | 5 | ~~~c++ 6 | template 7 | constexpr T make_from_tuple(Tuple&& t); 8 | ~~~ 9 | 10 | `apply`は`tuple`の要素を実引数に関数を呼び出すライブラリだが、`make_from_tuple`は`tuple`の要素を実引数にコンストラクターを呼び出すライブラリだ。 11 | 12 | ある型`T`と要素数`N`の`tuple t`に対して、`make_from_tuple(t)`は、`T`型を`T( get<0>(t), get<1>(t), ... , get(t) )`のように構築して、構築した`T`型のオブジェクトを返す。 13 | 14 | ~~~cpp 15 | class X 16 | { 17 | template < typename ... Types > 18 | T( Types ... ) { } 19 | } ; 20 | 21 | int main() 22 | { 23 | // int, int, int 24 | std::tuple t1(1,2,3) ; 25 | 26 | // X(1,2,3) 27 | X x1 = std::make_from_tuple( t1 ) 28 | 29 | // int, double, const char * 30 | std::tuple t2( 123, 4.56, "hello" ) ; 31 | 32 | // X(123, 4.56, "hello") 33 | X x2 = std::make_from_tuple( t2 ) ; 34 | } 35 | ~~~ 36 | -------------------------------------------------------------------------------- /055-cpp17-lib-misc-invoke.md: -------------------------------------------------------------------------------- 1 | ## invoke : 指定した関数を指定した実引数で呼び出す 2 | 3 | `invoke`はヘッダーファイル``で定義されている。 4 | 5 | ~~~c++ 6 | template 7 | invoke_result_t invoke(F&& f, Args&&... args) 8 | noexcept(is_nothrow_invocable_v); 9 | ~~~ 10 | 11 | `invoke( f, t1, t2, ... , tN )`は、関数`f`を`f( a1, a2, ... , aN )`のように呼び出す。 12 | 13 | より正確には、C++標準規格の`INVOKE(f, t1, t2, ... , tN)`と同じ規則で呼び出す。これにはさまざまな規則があり、たとえばメンバー関数へのポインターやデータメンバーへのポインター、またその場合に与えるクラスへのオブジェクトがリファレンスかポインターか`reference_wrapper`かによっても異なる。その詳細はここでは解説しない。 14 | 15 | `INVOKE`は`std::function`や`std::bind`でも使われている規則なので、標準ライブラリと同じ挙動ができるようになると覚えておけばよい。 16 | 17 | __例__: 18 | 19 | ~~~cpp 20 | void f( int ) { } 21 | 22 | struct S 23 | { 24 | void f( int ) ; 25 | int data ; 26 | } ; 27 | 28 | int main() 29 | { 30 | // f( 1 ) 31 | std::invoke( f, 1 ) ; 32 | 33 | S s ; 34 | 35 | // (s.*&S::f)(1) 36 | std::invoke( &S::f, s, 1 ) ; 37 | // ((*&s).*&S::f)(1) 38 | std::invoke( &S::f, &s, 1 ) ; 39 | // s.*&S::data 40 | std::invoke( &S::data, s ) ; 41 | } 42 | ~~~ 43 | -------------------------------------------------------------------------------- /056-cpp17-lib-misc-not-fn.md: -------------------------------------------------------------------------------- 1 | ## not_fn : 戻り値の否定ラッパー 2 | 3 | `not_fn`はヘッダーファイル``で定義されている。 4 | 5 | ~~~c++ 6 | template unspecified not_fn(F&& f); 7 | ~~~ 8 | 9 | 関数オブジェクト`f`に対して`not_fn(f)`を呼び出すと、戻り値として何らかの関数オブジェクトが返ってくる。その関数オブジェクトを呼び出すと、実引数を`f`に渡して`f`を関数呼び出しして、戻り値を`operator !`で否定して返す。 10 | 11 | ~~~cpp 12 | int main() 13 | { 14 | 15 | auto r1 = std::not_fn( []{ return true ; } ) ; 16 | 17 | r1() ; // false 18 | 19 | auto r2 = std::not_fn( []( bool b ) { return b ; } ) ; 20 | 21 | r2(true) ; // false 22 | } 23 | ~~~ 24 | 25 | すでに廃止予定になった`not1`, `not2`の代替品。 26 | -------------------------------------------------------------------------------- /057-cpp17-lib-misc-memory.md: -------------------------------------------------------------------------------- 1 | ## メモリー管理アルゴリズム 2 | 3 | C++17ではヘッダーファイル``にメモリー管理用のアルゴリズムが追加された。 4 | 5 | ### addressof 6 | 7 | ~~~c++ 8 | template constexpr T* addressof(T& r) noexcept; 9 | ~~~ 10 | 11 | `addressof`はC++17以前からもある。`addressof(r)`は`r`のポインターを取得する。たとえ、`r`の型が`operator &`をオーバーロードしていても正しいポインターを取得できる。 12 | 13 | ~~~cpp 14 | struct S 15 | { 16 | S * operator &() const noexcept 17 | { return nullptr ; } 18 | } ; 19 | 20 | int main() 21 | { 22 | S s ; 23 | 24 | // nullptr 25 | S * p1 = & s ; 26 | // 妥当なポインター 27 | S * p2 = std::addressof(s) ; 28 | 29 | } 30 | ~~~ 31 | 32 | ### uninitialized_default_construct 33 | 34 | ~~~c++ 35 | template 36 | void uninitialized_default_construct( 37 | ForwardIterator first, ForwardIterator last); 38 | 39 | template 40 | ForwardIterator uninitialized_default_construct_n( 41 | ForwardIterator first, Size n); 42 | ~~~ 43 | 44 | `[first, last)`の範囲、もしくは`first`から`n`個の範囲の未初期化のメモリーを`typename iterator_traits::value_type`でデフォルト初期化する。2つ目のアルゴリズムは`first`から`n`個をデフォルト初期化する。 45 | 46 | ~~~cpp 47 | int main() 48 | { 49 | std::shared_ptr raw_ptr 50 | ( ::operator new( sizeof(std::string) * 10 ), 51 | [](void * ptr){ ::operator delete(ptr) ; } ) ; 52 | 53 | std::string * ptr = static_cast( raw_ptr.get() ) ; 54 | 55 | std::uninitialized_default_construct_n( ptr, 10 ) ; 56 | std::destroy_n( ptr, 10 ) ; 57 | } 58 | ~~~ 59 | 60 | ### uninitialized_value_construct 61 | 62 | ~~~c++ 63 | template 64 | void uninitialized_value_construct( 65 | ForwardIterator first, ForwardIterator last); 66 | 67 | template 68 | ForwardIterator uninitialized_value_construct_n( 69 | ForwardIterator first, Size n); 70 | ~~~ 71 | 72 | 使い方は`uninitialized_default_construct`と同じ。ただし、こちらはデフォルト初期化ではなく値初期化する。 73 | 74 | ### uninitialized_copy 75 | 76 | ~~~c++ 77 | template 78 | ForwardIterator 79 | uninitialized_copy( InputIterator first, InputIterator last, 80 | ForwardIterator result); 81 | 82 | template 83 | ForwardIterator 84 | uninitialized_copy_n( InputIterator first, Size n, 85 | ForwardIterator result); 86 | ~~~ 87 | 88 | `[first, last)`の範囲、もしくは`first`から`n`個の範囲の値を、`result`の指す未初期化のメモリーにコピー構築する。 89 | 90 | ~~~cpp 91 | int main() 92 | { 93 | std::vector input(10, "hello") ; 94 | 95 | std::shared_ptr raw_ptr 96 | ( ::operator new( sizeof(std::string) * 10 ), 97 | [](void * ptr){ ::operator delete(ptr) ; } ) ; 98 | 99 | std::string * ptr = static_cast( raw_ptr.get() ) ; 100 | 101 | 102 | std::uninitialized_copy_n( std::begin(input), 10, ptr ) ; 103 | std::destroy_n( ptr, 10 ) ; 104 | } 105 | ~~~ 106 | 107 | ### uninitialized_move 108 | 109 | ~~~c++ 110 | template 111 | ForwardIterator 112 | uninitialized_move( InputIterator first, InputIterator last, 113 | ForwardIterator result); 114 | 115 | template 116 | pair 117 | uninitialized_move_n( InputIterator first, Size n, 118 | ForwardIterator result); 119 | ~~~ 120 | 121 | 使い方は`uninitialized_copy`と同じ。ただしこちらはコピーではなくムーブする。 122 | 123 | ### uninitialized_fill 124 | 125 | ~~~c++ 126 | template 127 | void uninitialized_fill( 128 | ForwardIterator first, ForwardIterator last, 129 | const T& x); 130 | 131 | template 132 | ForwardIterator uninitialized_fill_n( 133 | ForwardIterator first, Size n, 134 | const T& x); 135 | ~~~ 136 | 137 | `[first, last)`の範囲、もしくは`first`から`n`個の範囲の未初期化のメモリーを、コンストラクターに実引数`x`を与えて構築する。 138 | 139 | 140 | ### destroy 141 | 142 | ~~~c++ 143 | template 144 | void destroy_at(T* location); 145 | ~~~ 146 | 147 | `location->~T()`を呼び出す。 148 | 149 | ~~~c++ 150 | template 151 | void destroy(ForwardIterator first, ForwardIterator last); 152 | 153 | template 154 | ForwardIterator destroy_n(ForwardIterator first, Size n); 155 | ~~~ 156 | 157 | `[first, last)`の範囲、もしくは`first`から`n`個の範囲に`destroy_at`を呼び出す。 158 | -------------------------------------------------------------------------------- /058-cpp17-lib-misc-weak-ptr.md: -------------------------------------------------------------------------------- 1 | ## shared_ptr::weak_type 2 | 3 | C++17では`shared_ptr`に`weak_type`というネストされた型名が追加された。これは`shared_ptr`に対する`weak_ptr`の`typedef`名となっている。 4 | 5 | ~~~c++ 6 | namespace std { 7 | 8 | template < typename T > 9 | class shared_ptr 10 | { 11 | using weak_type = weak_ptr ; 12 | } ; 13 | 14 | } 15 | ~~~ 16 | 17 | __使い方__: 18 | 19 | ~~~cpp 20 | template < typename Shared_ptr > 21 | void f( Shared_ptr sptr ) 22 | { 23 | // C++14 24 | auto wptr1 = std::weak_ptr< 25 | typename Shared_ptr::element_type 26 | >( sptr ) ; 27 | 28 | // C++17 29 | auto wptr2 = typename Shared_ptr::weak_type( sptr ) ; 30 | } 31 | ~~~ 32 | -------------------------------------------------------------------------------- /059-cpp17-lib-misc-void-t.md: -------------------------------------------------------------------------------- 1 | ## void_t 2 | 3 | ヘッダーファイル``で定義されている`void_t`は以下のように定義されている。 4 | 5 | ~~~c++ 6 | namespace std { 7 | 8 | template < class ... > 9 | using void_t = void ; 10 | 11 | } 12 | ~~~ 13 | 14 | `void_t`は任意個の型をテンプレート実引数として受け取る`void`型だ。この性質はテンプレートメタプログラミングにおいてとても便利なので、標準ライブラリに追加された。 15 | -------------------------------------------------------------------------------- /060-cpp17-lib-misc-bool-constant.md: -------------------------------------------------------------------------------- 1 | ## bool_constant 2 | 3 | ヘッダーファイル``に`bool_constant`が追加された。 4 | 5 | ~~~c++ 6 | template 7 | using bool_constant = integral_constant; 8 | 9 | using true_type = bool_constant; 10 | using false_type = bool_constant; 11 | ~~~ 12 | 13 | 今まで`integral_constant`を使っていた場面で特に`bool`だけが必要な場面では、C++17以降は単に`std::true_type`か`std::false_type`と書くだけでよくなる。 14 | -------------------------------------------------------------------------------- /061-cpp17-lib-misc-traits.md: -------------------------------------------------------------------------------- 1 | ## type_traits 2 | 3 | C++17では``に機能追加が行われた。 4 | 5 | ### 変数テンプレート版traits 6 | 7 | C++17では、既存の`traits`に変数テンプレートを利用した`_v`版が追加された。 8 | 9 | たとえば、`is_integral::value`と書く代わりに`is_integral_v`と書くことができる。 10 | 11 | ~~~cpp 12 | template < typename T > 13 | void f( T x ) 14 | { 15 | constexpr bool b1 = std::is_integral::value ; // データメンバー 16 | constexpr bool b2 = std::is_integral_v ; // 変数テンプレート 17 | constexpr bool b3 = std::is_integral{} ; // operator bool() 18 | } 19 | ~~~ 20 | 21 | 22 | ### 論理演算traits 23 | 24 | C++17ではクラステンプレート`conjunction`, `disjunction`, `negation`が追加された。これはテンプレートメタプログラミングで論理積、論理和、否定を手軽に扱うための`traits`だ。 25 | 26 | #### conjunction : 論理積 27 | 28 | ~~~c++ 29 | template struct conjunction; 30 | ~~~ 31 | 32 | クラステンプレート`conjunction`はテンプレート実引数`B1`, `B2`, ..., `BN`に論理積を適用する。`conjunction`はそれぞれのテンプレート実引数`Bi`に対して、`bool(Bi::value)`が`false`となる最初の型を基本クラスに持つか、あるいは最後の`BN`を基本クラスに持つ。 33 | 34 | ~~~cpp 35 | int main() 36 | { 37 | using namespace std ; 38 | 39 | // is_voidを基本クラスに持つ 40 | using t1 = 41 | conjunction< 42 | is_same, is_integral, 43 | is_void > ; 44 | 45 | // is_integralを基本クラスに持つ 46 | using t2 = 47 | conjunction< 48 | is_same, is_integral, 49 | is_void > ; 50 | 51 | } 52 | ~~~ 53 | 54 | #### disjunction : 論理和 55 | 56 | 57 | ~~~c++ 58 | template struct disjunction; 59 | ~~~ 60 | 61 | 62 | クラステンプレート`disjunction`はテンプレート実引数`B1`, `B2`, ..., `BN`に論理和を適用する。`disjunction`はそれぞれのテンプレート実引数`Bi`に対して、`bool(Bi::value)`が`true`となる最初の型を基本クラスに持つか、あるいは最後の`BN`を基本クラスに持つ。 63 | 64 | ~~~cpp 65 | int main() 66 | { 67 | using namespace std ; 68 | 69 | // is_sameを基本クラスに持つ 70 | using t1 = 71 | disjunction< 72 | is_same, is_integral, 73 | is_void > ; 74 | 75 | // is_voidを基本クラスに持つ 76 | using t2 = 77 | disjunction< 78 | is_same, is_integral, 79 | is_void > ; 80 | } 81 | ~~~ 82 | 83 | ### negation : 否定 84 | 85 | ~~~c++ 86 | template struct negation; 87 | ~~~ 88 | 89 | クラステンプレート`negation`は`B`に否定を適用する。`negation`は基本クラスとして`bool_constant`を持つ。 90 | 91 | ~~~cpp 92 | int main() 93 | { 94 | using namespace std ; 95 | 96 | // false 97 | constexpr bool b1 = negation< true_type >::value ; 98 | // true 99 | constexpr bool b2 = negation< false_type >::value ; 100 | } 101 | ~~~ 102 | 103 | 104 | ### is_invocable : 呼び出し可能か確認するtraits 105 | 106 | 107 | ~~~c++ 108 | template 109 | struct is_invocable; 110 | 111 | template 112 | struct is_invocable_r; 113 | 114 | template 115 | struct is_nothrow_invocable; 116 | 117 | template 118 | struct is_nothrow_invocable_r; 119 | ~~~ 120 | 121 | 122 | `is_invocable`はテンプレート実引数で与えられた型`Fn`がパラメーターパック`ArgTypes`をパック展開した結果を実引数に関数呼び出しできるかどうか、そしてその戻り値は`R`へ暗黙変換できるかどうかを確認する`traits`だ。呼び出せるのであれば`true_type`, そうでなければ`false_type`を基本クラスに持つ。 123 | 124 | 125 | `is_invocable`は関数呼び出しした結果の戻り値の型については問わない。 126 | 127 | `is_invocable_r`は呼び出し可能性に加えて、関数呼び出しした結果の戻り値の型が`R`へ暗黙変換できることが確認される。 128 | 129 | `is_nothrow_invocable`と`is_nothrow_invocable_r`は、関数呼び出し(および戻り値型`R`への暗黙変換)が無例外保証されていることも確認する。 130 | 131 | ~~~cpp 132 | int f( int, double ) ; 133 | 134 | int main() 135 | { 136 | // true 137 | constexpr bool b1 = 138 | std::is_invocable< decltype(&f), int, double >{} ; 139 | // true 140 | constexpr bool b2 = 141 | std::is_invocable< decltype(&f), int, int >{} ; 142 | 143 | // false 144 | constexpr bool b3 = 145 | std::is_invocable< decltype(&f), int >{} ; 146 | // false 147 | constexpr bool b4 = 148 | std::is_invocable< decltype(&f), int, std::string >{} ; 149 | 150 | // true 151 | constexpr bool b5 = 152 | std::is_invocable_r< int, decltype(&f), int, double >{} ; 153 | // false 154 | constexpr bool b6 = 155 | std::is_invocable_r< double, decltype(&f), int, double >{} ; 156 | } 157 | ~~~ 158 | 159 | 160 | ### has_unique_object_representations : 同値の内部表現が同一か確認するtraits 161 | 162 | ~~~c++ 163 | template 164 | struct has_unique_object_representations ; 165 | ~~~ 166 | 167 | `has_unique_object_representations`は、`T`型がトリビアルにコピー可能で、かつ`T`型の同値である2つのオブジェクトの内部表現が同じ場合に、`true`を返す。 168 | 169 | `false`を返す例としては、オブジェクトがパディング(padding)と呼ばれるアライメント調整などのための値の表現に影響しないストレージ領域を持つ場合だ。パディングビットの値は同値に影響しないので、`false`を返す。 170 | 171 | たとえば以下のようなクラス`X`は、 172 | 173 | ~~~cpp 174 | struct X 175 | { 176 | std::uint8_t a ; 177 | std::uint32_t b ; 178 | } ; 179 | ~~~ 180 | 181 | ある実装においては、4バイトにアライメントする必要があり、そのオブジェクトの本当のレイアウトは以下のようになっているかもしれない。 182 | 183 | ~~~cpp 184 | struct X 185 | { 186 | std::uint8_t a ; 187 | 188 | std::byte unused_padding[3] ; 189 | 190 | std::uint32_t b ; 191 | } ; 192 | ~~~ 193 | 194 | この場合、`unused_padding`の値には意味がなく、クラス`X`の同値比較には用いられない。この場合、`std::has_unique_representations_v`は`false`になる。 195 | 196 | ### is_nothrow_swappable : 無例外swap可能か確認するtraits 197 | 198 | ~~~c++ 199 | template 200 | struct is_nothrow_swappable; 201 | 202 | template 203 | struct is_nothrow_swappable_with; 204 | ~~~ 205 | 206 | `is_nothrow_swappable`は`T`型が`swap`で例外を投げないときに`true`を返す。 207 | 208 | `is_nothrow_swappable_with`は、`T`型と`U`型を相互に`swap`するときに例外を投げないときに`true`を返す。 209 | -------------------------------------------------------------------------------- /062-cpp17-lib-misc-minimal-incomplete-type-support-for-containers.md: -------------------------------------------------------------------------------- 1 | ## コンテナーで不完全型のサポート 2 | 3 | __注意__:この説明は上級者向けだ。 4 | 5 | C++17では以下のコードが合法になった。このコードの挙動はC++14までは実装依存であった。 6 | 7 | ~~~cpp 8 | struct X 9 | { 10 | std::vector v ; 11 | std::list l ; 12 | std::forward_list f ; 13 | } ; 14 | ~~~ 15 | 16 | クラスはクラス定義の終了である`}`を持って完全型となる。クラススコープに注入されたクラス名は、クラス定義の中ではまだ完全型ではない。不完全型をコンテナーの要素型に指定した場合の挙動は、C++14までは規定されていなかった。 17 | 18 | C++17では、`vector`, `list`, `forward_list`に限り、要素型に一時的に不完全型を許すようになった。実際にコンテナーを使う際には完全型になっていなければならない。 19 | -------------------------------------------------------------------------------- /063-cpp17-lib-misc-emplace.md: -------------------------------------------------------------------------------- 1 | ## emplaceの戻り値 2 | 3 | C++17ではシーケンスコンテナーの`emplace_front`/`emplace_back`, `queue`と`stack`の`emplace`が構築した要素へのリファレンスを返すように変更された。 4 | 5 | そのため、C++14では以下のように書いていたコードが、 6 | 7 | ~~~cpp 8 | int main() 9 | { 10 | std::vector v ; 11 | 12 | v.emplace_back(0) ; // void 13 | int value = v.back() ; 14 | } 15 | ~~~ 16 | 17 | 以下のように書けるようになった。 18 | 19 | ~~~cpp 20 | int main() 21 | { 22 | std::vector v ; 23 | 24 | int value = v.emplace_back(0) ; 25 | } 26 | ~~~ 27 | -------------------------------------------------------------------------------- /064-cpp17-lib-misc-map.md: -------------------------------------------------------------------------------- 1 | ## mapとunordered_mapの変更 2 | 3 | `map`と`unordered_map`に、`try_emplace`と`insert_or_assign`という2つのメンバー関数が入った。このメンバー関数は`multi_map`と`unordered_multi_map`には追加されていない。 4 | 5 | ### try_emplace 6 | 7 | ~~~c++ 8 | template 9 | pair 10 | try_emplace(const key_type& k, Args&&... args); 11 | 12 | template 13 | iterator 14 | try_emplace( 15 | const_iterator hint, 16 | const key_type& k, Args&&... args); 17 | ~~~ 18 | 19 | 従来の`emplace`は、キーに対応する要素が存在しない場合、要素が`args`から`emplace`構築されて追加される。もし、キーに対応する要素が存在する場合、要素は追加されない。要素が追加されないとき、`args`がムーブされるかどうかは実装定義である。 20 | 21 | ~~~cpp 22 | int main() 23 | { 24 | std::map< int, std::unique_ptr > m ; 25 | 26 | // すでに要素が存在する 27 | m[0] = nullptr ; 28 | 29 | auto ptr = std::make_unique(0) ; 30 | // emplaceは失敗する 31 | auto [iter, is_emplaced] = m.emplace( 0, std::move(ptr) ) ; 32 | 33 | // 結果は実装により異なる 34 | // ptrはムーブされているかもしれない 35 | bool b = ( ptr != nullptr ) ; 36 | } 37 | ~~~ 38 | 39 | この場合、実際に`map`に要素は追加されていないのに、`ptr`はムーブされてしまうかもしれない。 40 | 41 | このため、C++17では、要素が追加されなかった場合`args`はムーブされないことが保証される`try_emplace`が追加された。 42 | 43 | ~~~cpp 44 | int main() 45 | { 46 | std::map< int, std::unique_ptr > m ; 47 | 48 | // すでに要素が存在する 49 | m[0] = nullptr ; 50 | 51 | auto ptr = std::make_unique(0) ; 52 | // try_emplaceは失敗する 53 | auto [iter, is_emplaced] = m.try_emplace( 0, std::move(ptr) ) ; 54 | 55 | // trueであることが保証される 56 | // ptrはムーブされていない 57 | bool b = ( ptr != nullptr ) ; 58 | } 59 | ~~~ 60 | 61 | ### insert_or_assign 62 | 63 | ~~~c++ 64 | template 65 | pair 66 | insert_or_assign(const key_type& k, M&& obj); 67 | 68 | template 69 | iterator 70 | insert_or_assign( 71 | const_iterator hint, 72 | const key_type& k, M&& obj); 73 | ~~~ 74 | 75 | `insert_or_assign`は`key`に連想された要素が存在する場合は要素を代入し、存在しない場合は要素を追加する。`operator []`との違いは、要素が代入されたか追加されたかが、戻り値の`pair`の`bool`でわかるということだ。 76 | 77 | ~~~cpp 78 | int main() 79 | { 80 | std::map< int, int > m ; 81 | m[0] = 0 ; 82 | 83 | { 84 | // 代入 85 | // is_insertedはfalse 86 | auto [iter, is_inserted] = m.insert_or_assign( 0, 1 ) ; 87 | } 88 | 89 | { 90 | // 追加 91 | // is_insertedはtrue 92 | auto [iter, is_inserted] = m.insert_or_assign( 1, 1 ) ; 93 | } 94 | } 95 | ~~~ 96 | -------------------------------------------------------------------------------- /066-cpp17-lib-misc-size.md: -------------------------------------------------------------------------------- 1 | ## コンテナーアクセス関数 2 | 3 | ヘッダーファイル``に、コンテナーアクセス関数として、フリー関数版の`size`, `empty`, `data`が追加された。それぞれ、メンバー関数の`size`, `empty`, `data`を呼び出す。 4 | 5 | ~~~cpp 6 | int main() 7 | { 8 | std::vector v ; 9 | 10 | std::size(v) ; // v.size() 11 | std::empty(v) ; // v.empty() 12 | std::data(v) ; // v.data() 13 | } 14 | ~~~ 15 | 16 | このフリー関数は配列や`std::initializer_list`にも使える。 17 | 18 | ~~~cpp 19 | int main() 20 | { 21 | int a[10] ; 22 | 23 | std::size(a) ; // 10 24 | std::empty(a) ; // 常にfalse 25 | std::data(a) ; // a 26 | } 27 | ~~~ 28 | -------------------------------------------------------------------------------- /067-cpp17-lib-misc-clamp.md: -------------------------------------------------------------------------------- 1 | ## clamp 2 | 3 | ~~~c++ 4 | template 5 | constexpr const T& 6 | clamp(const T& v, const T& lo, const T& hi); 7 | template 8 | constexpr const T& 9 | clamp(const T& v, const T& lo, const T& hi, Compare comp); 10 | ~~~ 11 | 12 | ヘッダーファイル``に追加された`clamp(v, lo, hi)`は値`v`が`lo`より小さい場合は`lo`を、`hi`より高い場合は`hi`を、それ以外の場合は`v`を返す。 13 | 14 | ~~~cpp 15 | int main() 16 | { 17 | std::clamp( 5, 0, 10 ) ; // 5 18 | std::clamp( -5, 0, 10 ) ; // 0 19 | std::clamp( 50, 0, 10 ) ; // 10 20 | } 21 | ~~~ 22 | 23 | `comp`を実引数に取る`clamp`は`comp`を値の比較に使う 24 | 25 | `clamp`には浮動小数点数も使えるが、NaNは渡せない。 26 | -------------------------------------------------------------------------------- /068-cpp17-lib-misc-hypot.md: -------------------------------------------------------------------------------- 1 | ## 3次元hypot 2 | 3 | ~~~c++ 4 | float hypot(float x, float y, float z); 5 | double hypot(double x, double y, double z); 6 | long double hypot(long double x, long double y, long double z); 7 | ~~~ 8 | 9 | ヘッダーファイル``に3次元の`hypot`が追加された。 10 | 11 | __戻り値__: 12 | 13 | $$ 14 | \sqrt{x^2+y^2+z^2} 15 | $$ 16 | -------------------------------------------------------------------------------- /069-cpp17-lib-misc-atomic-is-always-lock-free.md: -------------------------------------------------------------------------------- 1 | ## atomic\::is_always_lock_free 2 | 3 | ~~~c++ 4 | template < typename T > 5 | struct atomic 6 | { 7 | static constexpr bool is_always_lock_free = ... ; 8 | } ; 9 | ~~~ 10 | 11 | C++17で``に追加された`atomic::is_always_lock_free`は、`atomic`の実装がすべての実行においてロックフリーであるとコンパイル時に保証できる場合、`true`になる`static constexpr`な`bool`型のデータメンバーだ。 12 | 13 | `atomic`には、他にも`bool`を返すメンバー関数`is_lock_free`があるが、これは実行時にロックフリーであるかどうかを判定できる。`is_always_lock_free`はコンパイル時にロックフリーであるかどうかを判定できる。 14 | -------------------------------------------------------------------------------- /070-cpp17-misc-scoped-lock.md: -------------------------------------------------------------------------------- 1 | ## scoped_lock : 可変長引数lock_guard 2 | 3 | `std::scoped_lock`クラス``は可変長引数版の`lock_guard`だ。 4 | 5 | ~~~cpp 6 | int main() 7 | { 8 | std::mutex a, b, c, d ; 9 | 10 | { 11 | // a,b,c,dをlockする 12 | std::scoped_lock l( a, b, c, d ) ; 13 | // a,b,c,dをunlockする 14 | } 15 | } 16 | ~~~ 17 | 18 | `std::scoped_lock`のコンストラクターは複数のロックのオブジェクトのリファレンスを取り、それぞれにデッドロックを起こさない方法でメンバー関数`lock`を呼び出す。デストラクターはメンバー関数`unlock`を呼び出す。 19 | -------------------------------------------------------------------------------- /071-cpp17-misc-byte.md: -------------------------------------------------------------------------------- 1 | ## std::byte 2 | 3 | C++17ではバイトを表現する型として`std::byte`がライブラリに追加された。これは、コア言語の一部であり、[別項で詳しく解説を行っている](#std.byte)。 4 | -------------------------------------------------------------------------------- /072-cpp17-lib-misc-gcd-lcm.md: -------------------------------------------------------------------------------- 1 | ## 最大公約数(gcd)と最小公倍数(lcm) 2 | 3 | C++17ではヘッダーファイル``に最大公約数(`gcd`)と最小公倍数(`lcm`)が追加された。 4 | 5 | ~~~cpp 6 | int main() 7 | { 8 | int a, b ; 9 | 10 | while( std::cin >> a >> b ) 11 | { 12 | std::cout 13 | << "gcd: " << gcd(a,b) 14 | << "\nlcm: " << lcm(a,b) << '\n' ; 15 | } 16 | } 17 | ~~~ 18 | 19 | ### gcd : 最大公約数 20 | 21 | ~~~c++ 22 | template 23 | constexpr std::common_type_t gcd(M m, N n) 24 | { 25 | if ( n == 0 ) 26 | return m ; 27 | else 28 | return gcd( n, std::abs(m) % std::abs(n) ) ; 29 | } 30 | ~~~ 31 | 32 | `gcd(m, n)`は`m`と`n`がともにゼロの場合ゼロを返す。それ以外の場合、$|m|$と$|n|$の最大公約数(Greatest Common Divisor)を返す。 33 | 34 | ### lcm : 最小公倍数 35 | 36 | ~~~c++ 37 | template 38 | constexpr std::common_type_t lcm(M m, N n) 39 | { 40 | if ( m == 0 || n == 0 ) 41 | return 0 ; 42 | else 43 | return std::abs(m) / gcd( m, n ) * std::abs(n) ; 44 | } 45 | ~~~ 46 | 47 | `lcm(m,n)`は、`m`と`n`のどちらかがゼロの場合ゼロを返す。それ以外の場合、$|m|$と$|n|$の最小公倍数(Least Common Multiple)を返す。 48 | -------------------------------------------------------------------------------- /AsciiDWANGO/000-front.tex: -------------------------------------------------------------------------------- 1 | % 2 | % ## 本扉 3 | \thispagestyle{empty} 4 | \vbox to 0mm{\vspace*{-27.5truemm} 5 | \hbox to 0mm{ 6 | \hspace*{-23.8truemm}\includegraphics[width=154truemm]{tobira.eps} 7 | %\hspace*{-23.8truemm}\includegraphics[width=154truemm]{tobirac.eps} 8 | }\vss} 9 | 10 | %CPP17Book 11 | 12 | \pagebreak 13 | 14 | % 15 | % ## 商標 16 | \thispagestyle{frontheadings} 17 | 18 | \vbox to190mm{\hsize112mm 19 | \vfil 20 | \begin{minipage}[b]{112mm} 21 | % 22 | % ## 商標 23 | % \textgt{\textbf{商標}} 24 | \begin{spacing}{1.0} 25 | \begin{small} 26 | 本文中に記載されている社名および商品名は、一般に開発メーカーの登録商標です。\\ 27 | なお、本文中では\texttrademark ・\textcopyright ・\textregistered 表示を明記しておりません。 28 | \end{small} 29 | \end{spacing} 30 | \end{minipage} 31 | } 32 | 33 | -------------------------------------------------------------------------------- /AsciiDWANGO/000-preface.tex: -------------------------------------------------------------------------------- 1 | % 2 | % prologue 3 | \hyperchaptern{prologue}{はじめに} 4 | 5 | 本書は2017年に規格制定されたプログラミング言語C++の国際規格、ISO/IEC 6 | 14882:2017の新機能をほぼすべて解説している。 7 | 8 | 新しいC++17は不具合を修正し、プログラマーの日々のコーディングを楽にする新機能がいくつも追加された。その結果、C++の特徴であるパフォーマンスや静的型付けは損なうことなく、近年の動的な型の弱い言語に匹敵するほどの柔軟な記述を可能にしている。 9 | 10 | 人によっては、新機能を学ぶのは労多くして益少なしと考えるかもしれぬが、C++の新機能は現実の問題を解決するための便利な道具として追加されるもので、仮に機能を使わないとしても問題はなくならないため、便利な道具なく問題に対処しなければならぬ。また、C++の機能は一般的なプログラマーにとって自然だと感じるように設計されているため、利用は難しくない。もしC++が難しいと感じるのであれば、それはC++が解決すべき現実の問題が難しいのだ。なんとなれば、我々は理想とは程遠い歪なアーキテクチャのコンピューターを扱う時代に生きている。CPUの性能上昇は停滞し、メモリはCPUに比べて遥かに遅く、しかもそのアクセスは定数時間ではない。キャッシュに収まる局所性を持つデータへの操作は無料同然で、キャッシュサイズの単位はすでにMBで数えられている。手のひらに乗る超低電力CPUでさえマルチコアが一般的になり、並列処理、非同期処理は全プログラマーが考慮せねばならぬ問題になった。 11 | 12 | そのような時代にあたっては、かつては最良であった手法はその価値を失い、あるいは逆に悪い手法と成り下がる。同時に昔は現実的ではなかった手法が今ではかえってまともな方法になることさえある。このため、現在活発に使われている生きている言語は、常に時代に合わない機能を廃止し、必要な機能を追加する必要がある。C++の発展はここで留まることなく、今後もC++が使われ続ける限り、修正と機能追加が行われていくだろう。 13 | 14 | 本書の執筆はGithub上で公開して行われた。 15 | \vskip 0.5zw 16 | \hspace*{1em}\url{https://github.com/EzoeRyou/cpp17book} 17 | \vskip 0.5zw 18 | 本書のライセンスはGPLv3だ。 19 | 20 | 本書の執筆では株式会社ドワンゴとGitHub上でPull 21 | Requestを送ってくれた多くの貢献者の協力によって、誤りを正し、より良い記述を実現できた。この場を借りて謝意を表したい。 22 | 23 | 本書に誤りを見つけたならば、Pull 24 | Requestを送る先は 25 | \vskip 0.5zw 26 | \hspace*{1em}\url{https://github.com/EzoeRyou/cpp17book} 27 | \vskip 0.5zw 28 | \noindent 29 | だ。 30 | 31 | \vskip 1zw 32 | \begin{flushright} 33 | 江添亮 34 | \end{flushright} 35 | 36 | 37 | % 38 | % Preface 39 | \cleardoublepage 40 | \hyperchaptern{chapter0}{序} 41 | 42 | % 43 | % Section 0.1 44 | \hypersection{section0-1}{C++の規格} 45 | 46 | プログラミング言語C++はISOの傘下で国際規格ISO/IEC 47 | 14882として制定されている。この規格は数年おきに改定されている。一般にC++の規格を参照するときは、規格が制定した西暦の下二桁を取って、C++98(1998年発行)とかC++11(2011年発行)と呼ばれている。現在発行されているC++の規格は以下のとおり。 48 | \index{ぷろぐらみんぐげんごC++@プログラミング言語C++} 49 | \index{ISO/IEC 14882} 50 | 51 | % 52 | % SubSection 0.1.1 53 | \hypersubsection{section0-1-1}{C++98} 54 | \index{C++98} 55 | 56 | C++98は1998年に制定された最初のC++の規格である。本来ならば1994年か1995年には制定させる予定が大幅にずれて、1998年となった。 57 | 58 | % 59 | % SubSection 0.1.2 60 | \hypersubsection{section0-1-2}{C++03} 61 | \index{C++03} 62 | 63 | C++03はC++98の文面の曖昧な点を修正したマイナーアップデートとして2003年に制定された。新機能の追加はほとんどない。 64 | 65 | % 66 | % SubSection 0.1.3 67 | \hypersubsection{section0-1-3}{C++11} 68 | \index{C++11} 69 | 70 | C++11は制定途中のドラフト段階では元C++0xと呼ばれていた。これは、200x年までに規格が制定される予定だったからだ。予定は大幅に遅れ、ようやく規格が制定されたときにはすでに2011年の年末になっていた。C++11ではとても多くの新機能が追加された。 71 | 72 | % 73 | % SubSection 0.1.4 74 | \hypersubsection{section0-1-4}{C++14} 75 | \index{C++14} 76 | 77 | C++14は2014年に制定された。C++11の文面の誤りを修正した他、少し新機能が追加された。本書で解説する。 78 | 79 | % 80 | % SubSection 0.1.4 81 | \hypersubsection{section0-1-4}{C++17} 82 | \index{C++17} 83 | 84 | C++17は2017年に制定されることが予定されている最新のC++規格で、本書で解説する。 85 | 86 | % 87 | % Section 0.2 88 | \hypersection{section0-2}{C++の将来の規格} 89 | 90 | % 91 | % SubSection 0.2.1 92 | \hypersubsection{section0-2-1}{C++20} 93 | \index{C++20} 94 | 95 | C++20は2020年に制定されることが予定されている次のC++規格だ。この規格では、モジュール、コンセプト、レンジ、ネットワークに注力することが予定されている。 96 | 97 | % 98 | % Section 0.3 99 | \hypersection{section0-3}{コア言語とライブラリ} 100 | 101 | C++の標準規格は、大きく分けて、Cプリプロセッサーとコア言語とライブラリからなる。 102 | 103 | Cプリプロセッサーとは、C++がC言語から受け継いだ機能だ。ソースファイルをトークン列単位で分割して、トークン列の置換ができる。 104 | \index{Cぷりぷろせつさ@Cプリプロセッサー} 105 | 106 | コア言語とは、ソースファイルに書かれたトークン列の文法とその意味のことだ。 107 | \index{こあげんご@コア言語} 108 | 109 | ライブラリとは、コア言語機能を使って実装されたもので、標準に提供されているものだ。標準ライブラリには、純粋にコア言語の機能のみで実装できるものと、それ以外の実装依存の方法やコンパイラーマジックが必要なものとがある。 110 | \index{らいぶらり@ライブラリ} 111 | -------------------------------------------------------------------------------- /AsciiDWANGO/001-sd-6-feature-testing-recommendations.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Chapter 1 3 | \hyperchapter{chapter1}{SD-6 C++のための機能テスト推奨}{SD-6 C++のための\\機能テスト推奨} 4 | 5 | C++17には機能テストのためのCプリプロセッサー機能が追加された。 6 | \index{C++17}\index{きのうてすと@機能テスト}\index{Cぷりぷろせつさ@Cプリプロセッサー} 7 | 8 | % 9 | % Section 1.1 10 | \hypersection{section1-1}{機能テストマクロ} 11 | 12 | 機能テストというのは、C++の実装(C++コンパイラー)が特定の機能をサポートしているかどうかをコンパイル時に判断できる機能だ。本来、C++17の規格に準拠したC++実装は、C++17の機能をすべてサポートしているべきだ。しかし、残念ながら現実のC++コンパイラーの開発はそのようには行われていない。C++17に対応途中のC++コンパイラーは将来的にはすべての機能を実装することを目標としつつも、現時点では一部の機能しか実装していないという状態になる。 13 | 14 | たとえば、C++11で追加された\lstinline!rvalue!リファレンスという機能に現実のC++コンパイラーが対応しているかどうかをコンパイル時に判定するコードは以下のようになる。 15 | \index{rvalueりふあれんす@\texttt{rvalue}リファレンス} 16 | 17 | \begin{lstlisting}[language=C++] 18 | #ifndef __USE_RVALUE_REFERENCES 19 | #if (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 3) || \ 20 | _MSC_VER >= 1600 21 | #if __EDG_VERSION__ > 0 22 | #define __USE_RVALUE_REFERENCES (__EDG_VERSION__ >= 410) 23 | #else 24 | #define __USE_RVALUE_REFERENCES 1 25 | #endif 26 | #elif __clang__ 27 | #define __USE_RVALUE_REFERENCES __has_feature(cxx_rvalue_references) 28 | #else 29 | #define __USE_RVALUE_REFERENCES 0 30 | #endif 31 | #endif 32 | \end{lstlisting} 33 | 34 | このそびえ立つクソのようなコードは現実に書かれている。このコードはGCCとMSVCとEDGとClangという現実に使われている主要な4つのC++コンパイラーに対応した\lstinline!rvalue!リファレンスが実装されているかどうかを判定する機能テストコードだ。 35 | 36 | この複雑なプリプロセッサーを解釈した結果、\lstinline!__USE_RVALUE_REFERENCES!というプリプロセッサーマクロの値が、もしC++コンパイラーが\lstinline!rvalue!リファレンスをサポートしているならば1、そうでなければ0となる。後は、このプリプロセッサーマクロで~\lstinline!#if!~ガードしたコードを書く。 37 | \index{\_\_USE\_RVALUE\_REFERENCES@\texttt{\_\_USE\_RVALUE\_REFERENCES}} 38 | 39 | \begin{lstlisting}[language=C++] 40 | // 文字列を処理する関数 41 | void process_string( std::string const & str ) ; 42 | 43 | #if __USE_RVALUE_REFERENCES == 1 44 | // 文字列をムーブして処理してよい実装の関数 45 | // C++コンパイラーがrvalueリファレンスを実装していない場合はコンパイルされない 46 | void process_string( std::string && str ) ; 47 | #endif 48 | \end{lstlisting} 49 | 50 | C++17では、上のようなそびえ立つクソのようなコードを書かなくてもすむように、標準の機能テストマクロが用意された。C++実装が特定の機能をサポートしている場合、対応する機能テストマクロが定義される。機能テストマクロの値は、その機能がC++標準に採択された年と月を合わせた6桁の整数で表現される。 51 | \index{きのうてすとまくろ@機能テストマクロ} 52 | 53 | たとえば\lstinline!rvalue!リファレンスの場合、機能テストマクロの名前は\lstinline[breaklines=true]!__cpp_rvalue _references!となっている。\lstinline!rvalue!リファレンスは2006年10月に採択されたので、機能テストマクロの値は200610という値になっている。将来\lstinline!rvalue!リファレンスの機能が変更されたときは機能テストマクロの値も変更される。この値を調べることによって使っているC++コンパイラーはいつの時代のC++標準の機能をサポートしているか調べることもできる。 54 | \index{\_\_cpp\_rvalue\_references@\texttt{\_\_cpp\_rvalue\_references}} 55 | 56 | この機能テストマクロを使うと、上のコードの判定は以下のように書ける。 57 | 58 | \begin{lstlisting}[language=C++] 59 | // 文字列を処理する関数 60 | void process_string( std::string const & str ) ; 61 | 62 | #ifdef __cpp_rvalue_references 63 | // 文字列をムーブして処理してよい実装の関数 64 | // C++コンパイラーがrvalueリファレンスを実装していない場合はコンパイルされない 65 | void process_string( std::string && str ) ; 66 | #endif 67 | \end{lstlisting} 68 | 69 | 機能テストマクロの値は通常は気にする必要がない。機能テストマクロが存在するかどうかで機能の有無を確認できるので、通常は~\lstinline!#ifdef!~を使えばよい。 70 | 71 | % 72 | % Section 1.2 73 | \hypersection{section1-2}{\texttt{\_\_}has\texttt{\_}include式 : ヘッダーファイルの存在を判定する} 74 | \index{\_\_has\_includeしき@\texttt{\_\_has\_include}式}\index{へつだふあいるのそんざい@ヘッダーファイルの存在} 75 | 76 | \lstinline!__has_include!式は、ヘッダーファイルが存在するかどうかを調べるための機能だ。 77 | 78 | \begin{lstlisting}[language=C++] 79 | __has_include( ヘッダー名 ) 80 | \end{lstlisting} 81 | 82 | \lstinline!__has_include!式はヘッダー名が存在する場合1に、存在しない場合0に置換される。 83 | 84 | たとえば、C++17の標準ライブラリにはファイルシステムが入る。そのヘッダー名は~\lstinline!!~だ。C++コンパイラーがファイルシステムライブラリをサポートしているかどうかを調べるには、以下のように書く。 85 | 86 | \begin{lstlisting}[language=C++] 87 | #if __has_include() 88 | // ファイルシステムをサポートしている 89 | #include 90 | namespace fs = std::filesystem ; 91 | #else 92 | // 実験的な実装を使う 93 | #include 94 | namespace fs = std::experimental::filesystem ; 95 | #endif 96 | \end{lstlisting} 97 | 98 | C++実装が\lstinline!__has_include!をサポートしているかどうかは、\lstinline!__has_include!の存在をプリプロセッサーマクロのように~\lstinline!#ifdef!~で調べることによって判定できる。 99 | 100 | \begin{lstlisting}[language=C++] 101 | #ifdef __has_include 102 | // __has_includeをサポートしている 103 | #else 104 | // __has_includeをサポートしていない 105 | #endif 106 | \end{lstlisting} 107 | 108 | \lstinline!__has_include!式は~\lstinline!#if!~と~\lstinline!#elif!~の中でしか使えない。 109 | 110 | \begin{lstlisting}[language=C++] 111 | int main() 112 | { 113 | // エラー 114 | if ( __has_include() ) 115 | { } 116 | } 117 | \end{lstlisting} 118 | 119 | % 120 | % Section 1.3 121 | \hypersection{section1-3}{\texttt{\_\_}has\texttt{\_}cpp\texttt{\_}attribute式} 122 | \index{\_\_has\_cpp\_attributeしき@\texttt{\_\_has\_cpp\_attribute}式} 123 | 124 | C++実装が特定の属性トークンをサポートしているかどうかを調べるには、\lstinline!__has_cpp_attribute!式が使える。 125 | \index{ぞくせいとくん@属性トークン} 126 | 127 | \begin{lstlisting}[language=C++] 128 | __has_cpp_attribute( 属性トークン ) 129 | \end{lstlisting} 130 | 131 | \lstinline!__has_cpp_attribute!式は、属性トークンが存在する場合は属性トークンが標準規格に採択された年と月を表す数値に、存在しない場合は0に置換される。 132 | 133 | \begin{lstlisting}[language=C++] 134 | // [[nodiscard]]がサポートされている場合は使う 135 | #if __has_cpp_attribute(nodiscard) 136 | [[nodiscard]] 137 | #endif 138 | void * allocate_memory( std::size_t size ) ; 139 | \end{lstlisting} 140 | 141 | \lstinline!__has_include!式と同じく、\lstinline!__has_cpp_attribute!式も~\lstinline!#if!~か~\lstinline!#elif!~の中でしか使えない。\lstinline!#ifdef!~で\lstinline!__has_cpp_attribute!式の存在の有無を判定できる。 142 | -------------------------------------------------------------------------------- /AsciiDWANGO/002-cpp14-core.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Chapter 2 3 | \hyperchapter{chapter2}{C++14のコア言語の新機能}{C++14のコア言語の新機能} 4 | 5 | C++14で追加された新機能は少ない。C++14はC++03と同じくマイナーアップデートという位置付けで積極的な新機能の追加は見送られたからだ。 6 | \index{C++14}\index{C++14!こあげんご@コア言語} 7 | -------------------------------------------------------------------------------- /AsciiDWANGO/003-cpp14-core-binary-literals.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 2.1 3 | \hypersection{section2-1}{二進数リテラル} 4 | 5 | 二進数リテラルは整数リテラルを二進数で記述する機能だ。整数リテラルのプレフィクスに\lstinline!0B!もしくは\lstinline!0b!を書くと、二進数リテラルになる。整数を表現する文字は0と1しか使えない。 6 | \index{にしんすうりてらる@二進数リテラル}\index{\texttt{0B}}\index{\texttt{0b}} 7 | 8 | \begin{lstlisting}[language=C++] 9 | int main() 10 | { 11 | int x1 = 0b0 ; // 0 12 | int x2 = 0b1 ; // 1 13 | int x3 = 0b10 ; // 2 14 | int x4 = 0b11001100 ; // 204 15 | } 16 | \end{lstlisting} 17 | 18 | 二進数リテラルは浮動小数点数リテラルには使えない。 19 | 20 | 機能テストマクロは~\lstinline!__cpp_binary_literals!, 値は201304。 21 | \index{\_\_cpp\_binary\_literals@\texttt{\_\_cpp\_binary\_literals}} 22 | -------------------------------------------------------------------------------- /AsciiDWANGO/004-cpp14-core-digit-separator.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 2.2 3 | \hypersection{section2-2}{数値区切り文字} 4 | 5 | 数値区切り文字は、整数リテラルと浮動小数点数リテラルの数値をシングルクオート文字で区切ることができる機能だ。区切り桁は何桁でもよい。 6 | \index{すうちくぎりもじ@数値区切り文字} 7 | 8 | \begin{lstlisting}[language=C++] 9 | int main() 10 | { 11 | int x1 = 123'456'789 ; 12 | int x2 = 1'2'3'4'5'6'7'8'9 ; 13 | int x3 = 1'2345'6789 ; 14 | int x4 = 1'23'456'789 ; 15 | 16 | double x5 = 3.14159'26535'89793 ; 17 | } 18 | \end{lstlisting} 19 | 20 | 大きな数値を扱うとき、ソースファイルに\lstinline!100000000!と\lstinline!1000000000!と書かれていた場合、どちらが大きいのか人間の目にはわかりにくい。人間が読んでわかりにくいコードは間違いの元だ。数値区切りを使うと、\lstinline!100'000'000と1'000'000'000!のように書くことができる。これはわかりやすい。 21 | 22 | 他には、1バイト単位で見やすいように区切ることもできる。 23 | 24 | \begin{lstlisting}[language=C++] 25 | int main() 26 | { 27 | unsigned int x1 = 0xde'ad'be'ef ; 28 | unsigned int x2 = 0b11011110'10101101'10111110'11101111 ; 29 | } 30 | \end{lstlisting} 31 | 32 | 数値区切りはソースファイルを人間が読みやすくするための機能で、数値に影響を与えない。 33 | -------------------------------------------------------------------------------- /AsciiDWANGO/005-cpp14-core-deprecated-attribute.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 2.3 3 | \hypersection{section2-3}{{[}{[}deprecated{]}{]}属性} 4 | 5 | \lstinline![[deprecated]]!属性は名前とエンティティが、まだ使えるものの利用は推奨されない状態であることを示すのに使える。\lstinline![[deprecated]]!属性が指定できる名前とエンティティは、クラス、\lstinline!typedef!名、変数、非\lstinline!static!データメンバー、関数、名前空間、\lstinline!enum!, 6 | \lstinline!enumerator!, テンプレートの特殊化だ。 7 | \index{[[deprecated]]ぞくせい@\texttt{[[deprecated]]}属性} 8 | 9 | それぞれ以下のように指定できる。 10 | 11 | \begin{lstlisting}[language=C++] 12 | // 変数 13 | // どちらでもよい 14 | [[deprecated]] int variable_name1 { } ; 15 | int variable_name2 [[deprecated]] { } ; 16 | 17 | // typedef名 18 | [[deprecated]] typedef int typedef_name1 ; 19 | typedef int typedef_name2 [[deprecated]] ; 20 | using typedef_name3 [[deprecated]] = int ; 21 | 22 | // 関数 23 | // メンバー関数も同じ文法 24 | // どちらでもよい 25 | [[deprecated]] void function_name1() { } 26 | void function_name2 [[deprecated]] () { } 27 | 28 | 29 | // クラス 30 | // unionも同じ 31 | class [[deprecated]] class_name 32 | { 33 | // 非staticデータメンバー 34 | [[deprecated]] int non_static_data_member_name ; 35 | } ; 36 | 37 | // enum 38 | enum class [[deprecated]] enum_name 39 | { 40 | // enumerator 41 | enumerator_name [[deprecated]] = 42 42 | } ; 43 | 44 | 45 | // 名前空間 46 | namespace [[deprecated]] namespace_name { int x ; } 47 | 48 | // テンプレートの特殊化 49 | 50 | template < typename T > 51 | class template_name { } ; 52 | 53 | template < > 54 | class [[deprecated]] template_name { } ; 55 | \end{lstlisting} 56 | 57 | \lstinline![[deprecated]]!属性が指定された名前やエンティティを使うと、C++コンパイラーは警告メッセージを出す。 58 | 59 | \lstinline![[deprecated]]!属性には、文字列を付け加えることができる。これはC++実装によっては警告メッセージに含まれるかもしれない。 60 | 61 | \begin{lstlisting}[language=C++] 62 | [[deprecated("Use of f() is deprecated. Use f(int option) instead.")]] 63 | void f() ; 64 | 65 | void f( int option ) ; 66 | \end{lstlisting} 67 | 68 | 機能テストマクロは~\lstinline!__has_cpp_attribute(deprecated)!, 69 | 値は201309。 70 | \index{\_\_has\_cpp\_attribute(deprecated)@\texttt{\_\_has\_cpp\_attribute(deprecated)}} 71 | -------------------------------------------------------------------------------- /AsciiDWANGO/006-cpp14-core-return-type-deduction-for-normal-function.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 2.4 3 | \hypersection{section2-4}{通常の関数の戻り値の型推定} 4 | \index{かんすうのもどりちのかたすいてい@関数の戻り値の型推定} 5 | 6 | 関数の戻り値の型として\lstinline!auto!を指定すると、戻り値の型を\lstinline!return!文から推定してくれる。 7 | \index{auto@\texttt{auto}} 8 | 9 | \begin{lstlisting}[language=C++] 10 | // int () 11 | auto a(){ return 0 ; } 12 | // double () 13 | auto b(){ return 0.0 ; } 14 | 15 | // T(T) 16 | template < typename T > 17 | auto c(T t){ return t ; } 18 | \end{lstlisting} 19 | 20 | \lstinline!return!文の型が一致していないとエラーとなる。 21 | 22 | \begin{lstlisting}[language=C++] 23 | auto f() 24 | { 25 | return 0 ; // エラー、一致していない 26 | return 0.0 ; // エラー、一致していない 27 | } 28 | \end{lstlisting} 29 | 30 | すでに型が決定できる\lstinline!return!文が存在する場合、関数の戻り値の型を参照するコードも書ける。 31 | 32 | \begin{lstlisting}[language=C++] 33 | auto a() 34 | { 35 | &a ; // エラー、aの戻り値の型が決定していない 36 | return 0 ; 37 | } 38 | 39 | auto b() 40 | { 41 | return 0 ; 42 | &b ; // OK、戻り値の型はint 43 | } 44 | \end{lstlisting} 45 | 46 | 関数\lstinline!a!へのポインターを使うには関数\lstinline!a!の型が決定していなければならないが、\lstinline!return!文の前に型は決定できないので関数\lstinline!a!はエラーになる。関数\lstinline!b!は\lstinline!return!文が現れた後なので戻り値の型が決定できる。 47 | 48 | 再帰関数も書ける。 49 | 50 | \begin{lstlisting}[language=C++] 51 | auto sum( unsigned int i ) 52 | { 53 | if ( i == 0 ) 54 | return i ; // 戻り値の型はunsigned int 55 | else 56 | return sum(i-1)+i ; // OK 57 | } 58 | \end{lstlisting} 59 | 60 | このコードも、\lstinline!return!文の順番を逆にすると戻り値の型が決定できずエラーとなるので注意。 61 | 62 | \begin{lstlisting}[language=C++] 63 | auto sum( unsigned int i ) 64 | { 65 | if ( i != 0 ) 66 | return sum(i-1)+i ; // エラー 67 | else 68 | return i ; 69 | } 70 | \end{lstlisting} 71 | 72 | 機能テストマクロは~\lstinline!__cpp_return_type_deduction!, 値は201304。 73 | \index{\_\_cpp\_return\_type\_deduction@\texttt{\_\_cpp\_return\_type\_deduction}} 74 | -------------------------------------------------------------------------------- /AsciiDWANGO/007-cpp14-core-decltype-auto.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 2.5 3 | \hypersection{section2-5}{decltype(auto) : 厳格なauto} 4 | \index{decltype(auto)@\texttt{decltype(auto)}}\index{げんかくなauto@厳格な\texttt{auto}}\index{auto@\texttt{auto}!げんかくな@厳格な〜} 5 | 6 | \noindent 7 | \textsf{警告}:この項目はC++規格の詳細な知識を解説しているため極めて難解になっている。平均的なC++プログラマーはこの知識を得てもよりよいコードが書けるようにはならない。この項目は読み飛ばすべきである。 8 | 9 | \lstinline!decltype(auto)!は\lstinline!auto!指定子の代わりに使える厳格な\lstinline!auto!だ。利用にはC++の規格の厳格な理解が求められる。 10 | 11 | \lstinline!auto!と\lstinline!decltype(auto)!は型指定子と呼ばれる文法の一種で、プレイスホルダー型として使う。 12 | \index{かたしていし@型指定子}\index{ぷれいすほるだがた@プレイスホルダー型} 13 | 14 | わかりやすく言うと、具体的な型を式から決定する機能だ。 15 | 16 | \begin{lstlisting}[language=C++] 17 | // aはint 18 | auto a = 0 ; 19 | // bはint 20 | auto b() { return 0 ; } 21 | \end{lstlisting} 22 | 23 | 変数宣言にプレイスホルダー型を使う場合、型を決定するための式は初期化子と呼ばれる部分に書かれる式を使う。関数の戻り値の型推定にプレイスホルダー型を使う場合、\lstinline!return!文の式を使う。 24 | 25 | \lstinline!decltype(auto)!は\lstinline!auto!の代わりに使うことができる。\lstinline!decltype(auto)!も型を式から決定する。 26 | 27 | \begin{lstlisting}[language=C++] 28 | // aはint 29 | decltype(auto) a = 0 ; 30 | // bはint 31 | decltype(auto) b() { return 0 ; } 32 | \end{lstlisting} 33 | 34 | 一見すると\lstinline!auto!と\lstinline!decltype(auto)!は同じようだ。しかし、この2つは式から型を決定する方法が違う。どちらもC++の規格の極めて難しい規則に基づいて決定される。習得には熟練の魔法使いであることが要求される。 35 | 36 | \lstinline!auto!が式から型を決定するには、\lstinline!auto!キーワードをテンプレートパラメーター名で置き換えた関数テンプレートの仮引数に、式を実引数として渡してテンプレート実引数推定を行わせた場合に推定される型が使われる。 37 | 38 | たとえば 39 | \begin{lstlisting}[language=C++] 40 | auto x = 0 ; 41 | \end{lstlisting} 42 | の場合は、 43 | \begin{lstlisting}[language=C++] 44 | template < typename T > 45 | void f( T u ) ; 46 | \end{lstlisting} 47 | のような関数テンプレートに対して、 48 | \begin{lstlisting}[language=C++] 49 | f(0) ; 50 | \end{lstlisting} 51 | と実引数を渡したときに\lstinline!u!の型として推定される型と同じ型になる。 52 | 53 | \begin{lstlisting}[language=C++] 54 | int i ; 55 | auto const * x = &i ; 56 | \end{lstlisting} 57 | の場合には、 58 | \begin{lstlisting}[language=C++] 59 | template < typename T > 60 | void f( T const * u ) ; 61 | \end{lstlisting} 62 | のような関数テンプレートに 63 | \begin{lstlisting}[language=C++] 64 | f(&i) ; 65 | \end{lstlisting} 66 | と実引数を渡したときに\lstinline!u!の型として推定される型と同じ型になる。この場合は~\lstinline!int const *!~になる。 67 | 68 | ここまでが\lstinline!auto!の説明だ。\lstinline!decltype(auto)!の説明は簡単だ。 69 | 70 | \lstinline!decltype(auto)!の型は、\lstinline!auto!を式で置き換えた\lstinline!decltype!の型になる。 71 | 72 | \begin{lstlisting}[language=C++] 73 | // int 74 | decltype(auto) a = 0 ; 75 | 76 | // int 77 | decltype(auto) f() { return 0 ; } 78 | \end{lstlisting} 79 | 80 | 上のコードは、下のコードと同じ意味だ。 81 | 82 | \begin{lstlisting}[language=C++] 83 | decltype(0) a = 0 ; 84 | decltype(0) f() { return 0 ; } 85 | \end{lstlisting} 86 | 87 | ここまでは簡単だ。そして、これ以降は黒魔術のようなC++の規格の知識が必要になってくる。 88 | 89 | \lstinline!auto!と\lstinline!decltype(auto)!は一見すると同じように見える。型を決定する方法として、\lstinline!auto!は関数テンプレートの実引数推定を使い、\lstinline!decltype(auto)!は\lstinline!decltype!を使う。どちらも式を評価した結果の型になる。いったい何が違うというのか。 90 | 91 | 主な違いは、\lstinline!auto!は関数呼び出しを使うということだ。関数呼び出しの際にはさまざまな暗黙の型変換が行われる。 92 | 93 | たとえば、配列を関数に渡すと、暗黙の型変換の結果、配列の先頭要素へのポインターになる。 94 | 95 | \begin{lstlisting}[language=C++] 96 | template < typename T > 97 | void f( T u ) {} 98 | 99 | int main() 100 | { 101 | int array[5] ; 102 | // Tはint * 103 | f( array ) ; 104 | } 105 | \end{lstlisting} 106 | 107 | では\lstinline!auto!と\lstinline!decltype(auto)!を使うとどうなるのか。 108 | 109 | \begin{lstlisting}[language=C++] 110 | int array[5] ; 111 | // int * 112 | auto x1 = array ; 113 | // エラー、配列は配列で初期化できない 114 | decltype(auto) x2 = array ; 115 | \end{lstlisting} 116 | 117 | このコードは、以下と同じ意味になる。 118 | 119 | \begin{lstlisting}[language=C++] 120 | int array[5] ; 121 | // int * 122 | int * x1 = array ; 123 | // エラー、配列は配列で初期化できない 124 | int x2[5] = array ; 125 | \end{lstlisting} 126 | 127 | \lstinline!auto!の場合、型は\lstinline!int *!となる。配列は配列の先頭要素へのポインターへと暗黙に変換できるので、結果のコードは正しい。 128 | 129 | \lstinline!decltype(auto)!の場合、型は\lstinline!int [5]!となる。配列は配列で初期化、代入ができないので、このコードはエラーになる。 130 | 131 | 関数型も暗黙の型変換により関数へのポインター型になる。 132 | 133 | \begin{lstlisting}[language=C++] 134 | void f() ; 135 | 136 | // 型はvoid(*)() 137 | auto x1 = f ; 138 | // エラー、関数型は変数にできない 139 | decltype(auto) x2 = f ; 140 | \end{lstlisting} 141 | 142 | \lstinline!auto!はトップレベルのリファレンス修飾子を消すが、\lstinline!decltype(auto)!は保持する。 143 | 144 | \begin{lstlisting}[language=C++] 145 | int & f() 146 | { 147 | static int x ; 148 | return x ; 149 | } 150 | 151 | int main() 152 | { 153 | // int 154 | auto x1 = f() ; 155 | // int & 156 | decltype(auto) x2 = f() ; 157 | } 158 | \end{lstlisting} 159 | 160 | リスト初期化は\lstinline!auto!では\lstinline!std::initializer_list!だが、\lstinline!decltype(auto)!では式ではないためエラー。 161 | 162 | \begin{lstlisting}[language=C++] 163 | int main() 164 | { 165 | // std::initializer_list 166 | auto x1 = { 1,2,3 } ; 167 | // エラー、decltype({1,2,3})はできない 168 | decltype(auto) x2 = { 1,2,3 } ; 169 | } 170 | \end{lstlisting} 171 | 172 | \lstinline!decltype(auto)!は単体で使わなければならない。 173 | 174 | \begin{lstlisting}[language=C++] 175 | // OK 176 | auto const x1 = 0 ; 177 | // エラー 178 | decltype(auto) const x2 = 0 ; 179 | \end{lstlisting} 180 | 181 | この他にも\lstinline!auto!と\lstinline!decltype(auto)!にはさまざまな違いがある。すべての違いを列挙するのは煩雑なので省略するが、\lstinline!decltype(auto)!は式の型を直接使う。\lstinline!auto!はたいていの場合は便利な型の変換が入る。 182 | 183 | \lstinline!auto!は便利でたいていの場合はうまくいくが暗黙の型の変換が入るため、意図どおりの推定をしてくれないことがある。 184 | 185 | たとえば、引数でリファレンスを受け取り、戻り値でそのリファレンスを返す関数を書くとする。以下のように書くのは間違いだ。 186 | 187 | \begin{lstlisting}[language=C++] 188 | // int ( int & ) 189 | auto f( int & ref ) 190 | { return ref ; } 191 | \end{lstlisting} 192 | 193 | なぜならば、戻り値の型は式の型から変化して\lstinline!int!になってしまうからだ。ここで\lstinline!decltype(auto)!を使うと、 194 | \begin{lstlisting}[language=C++] 195 | // int & ( int & ) 196 | decltype(auto) f( int & ref ) 197 | { return ref ; } 198 | \end{lstlisting} 199 | 式の型をそのまま使ってくれる。 200 | 201 | ラムダ式に\lstinline!decltype(auto)!を使う場合は以下のように書く。 202 | 203 | \begin{lstlisting}[language=C++] 204 | []() -> decltype(auto) { return 0 ; } ; 205 | \end{lstlisting} 206 | 207 | \lstinline!decltype(auto)!は主に関数の戻り値の型推定で式の型をそのまま推定してくれるようにするために追加された機能だ。その利用にはC++の型システムの深い理解が必要になる。 208 | 209 | 機能テストマクロは~\lstinline!__cpp_decltype_auto!, 値は201304。 210 | \index{\_\_cpp\_decltype\_auto@\texttt{\_\_cpp\_decltype\_auto}} 211 | -------------------------------------------------------------------------------- /AsciiDWANGO/008-cpp14-core-generic-lambda.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 2.6 3 | \hypersection{section2-6}{ジェネリックラムダ} 4 | 5 | ジェネリックラムダはラムダ式の引数の型を書かなくてもすむようにする機能だ。 6 | \index{じえねりつくらむだ@ジェネリックラムダ}\index{らむだしき@ラムダ式} 7 | 8 | 通常のラムダ式は以下のように書く。 9 | 10 | \begin{lstlisting}[language=C++] 11 | int main() 12 | { 13 | []( int i, double d, std::string s ) { } ; 14 | } 15 | \end{lstlisting} 16 | 17 | ラムダ式の引数には型が必要だ。しかし、クロージャーオブジェクトの\lstinline!operator ()!に渡す型はコンパイル時にわかる。コンパイル時にわかるということはわざわざ人間が指定する必要はない。ジェネリックラムダを使えば、引数の型を書くべき場所に\lstinline!auto!キーワードを書くだけで型を推定してくれる。 18 | \index{くろじやおぶじえくと@クロージャーオブジェクト}\index{operator ()@\texttt{operator ()}} 19 | 20 | \begin{lstlisting}[language=C++] 21 | int main() 22 | { 23 | []( auto i, auto d, auto s ) { } ; 24 | } 25 | \end{lstlisting} 26 | 27 | ジェネリックラムダ式の結果のクロージャー型には呼び出しごとに違う型を渡すことができる。 28 | \index{くろじやがた@クロージャー型} 29 | 30 | \begin{lstlisting}[language=C++] 31 | int main() 32 | { 33 | auto f = []( auto x ) { std::cout << x << '\n' ; } ; 34 | 35 | f( 123 ) ; // int 36 | f( 12.3 ) ; // double 37 | f( "hello" ) ; // char const * 38 | } 39 | \end{lstlisting} 40 | 41 | 仕組みは簡単で、以下のようなメンバーテンプレートの\lstinline!operator ()!を持ったクロージャーオブジェクトが生成されているだけだ。 42 | 43 | \begin{lstlisting}[language=C++] 44 | struct closure_object 45 | { 46 | template < typename T > 47 | auto operator () ( T x ) 48 | { 49 | std::cout << x << '\n' ; 50 | } 51 | } ; 52 | \end{lstlisting} 53 | 54 | 機能テストマクロは~\lstinline!__cpp_generic_lambdas!, 値は201304。 55 | \index{\_\_cpp\_generic\_lambdas@\texttt{\_\_cpp\_generic\_lambdas}} 56 | -------------------------------------------------------------------------------- /AsciiDWANGO/009-cpp14-core-init-lambda-capture.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 2.7 3 | \hypersection{section2-7}{初期化ラムダキャプチャー} 4 | 5 | 初期化ラムダキャプチャーはラムダキャプチャーする変数の名前と式を書くことができる機能だ。 6 | \index{しよきからむだきやぷちや@初期化ラムダキャプチャー}\index{らむだきやぷちや@ラムダキャプチャー} 7 | 8 | ラムダ式は書かれた場所から見えるスコープの変数をキャプチャーする。 9 | \index{らむだしき@ラムダ式} 10 | 11 | \begin{lstlisting}[language=C++] 12 | int main() 13 | { 14 | int x = 0 ; 15 | auto f = [=]{ return x ; } ; 16 | f() ; 17 | } 18 | \end{lstlisting} 19 | 20 | 初期化ラムダキャプチャーはラムダキャプチャーに初期化子を書くことができる機能だ。 21 | 22 | \begin{lstlisting}[language=C++] 23 | int main() 24 | { 25 | int x = 0 ; 26 | [ x = x, y = x, &ref = x, x2 = x * 2 ] 27 | {// キャプチャーされた変数を使う 28 | x ; 29 | y ; 30 | ref ; 31 | x2 ; 32 | } ; 33 | } 34 | \end{lstlisting} 35 | 36 | 初期化ラムダキャプチャーは、``識別子 \lstinline!= expr!''という文法でラムダ導入子\lstinline![]!の中に書く。するとあたかも``\lstinline!auto!~識別子~\lstinline!= expr ;!''と書いたかのように変数が作られる。これによりキャプチャーする変数の名前を変えたり、まったく新しい変数を宣言することができる。 37 | 38 | 初期化ラムダキャプチャーの識別子の前に~\lstinline!&!~を付けると、リファレンスキャプチャー扱いになる。 39 | \index{りふあれんすきやぷちや@リファレンスキャプチャー} 40 | 41 | \begin{lstlisting}[language=C++] 42 | int main() 43 | { 44 | int x = 0 ; 45 | [ &ref = x ]() 46 | { 47 | ref = 1 ; 48 | }() ; 49 | 50 | // xは1 51 | } 52 | \end{lstlisting} 53 | 54 | 初期化ラムダキャプチャーが追加された理由には変数の名前を変えたりまったく新しい変数を導入したいという目的の他に、非\lstinline!static!データメンバーをコピーキャプチャーするという目的がある。 55 | \index{こぴきやぷちや@コピーキャプチャー} 56 | 57 | 以下のコードには問題があるが、わかるだろうか。 58 | 59 | \begin{lstlisting}[language=C++] 60 | struct X 61 | { 62 | int data = 42 ; 63 | 64 | auto get_closure_object() 65 | { 66 | return [=]{ return data ; } ; 67 | } 68 | } ; 69 | 70 | 71 | int main() 72 | { 73 | std::function< int() > f ; 74 | 75 | { 76 | X x ; 77 | f = x.get_closure_object() ; 78 | } 79 | 80 | std::cout << f() << std::endl ; 81 | } 82 | \end{lstlisting} 83 | 84 | \lstinline!X::get_closure_object!は\lstinline!X::data!を返すクロージャーオブジェクトを返す。 85 | 86 | \begin{lstlisting}[language=C++] 87 | auto get_closure_object() 88 | { 89 | return [=]{ return data ; } ; 90 | } 91 | \end{lstlisting} 92 | 93 | これを見ると、コピーキャプチャーである\lstinline![=]!を使っているので、\lstinline!data!はクロージャーオブジェクト内にコピーされているように思える。しかし、ラムダ式は非\lstinline!static!データメンバーをキャプチャーしてはいない。ラムダ式がキャプチャーしているのは\lstinline!this!ポインターだ。上のコードと下のコードは同じ意味になる。 94 | 95 | \begin{lstlisting}[language=C++] 96 | auto get_closure_object() 97 | { 98 | return [this]{ return this->data ; } ; 99 | } 100 | \end{lstlisting} 101 | 102 | さて、\lstinline!main!関数をもう一度見てみよう。 103 | 104 | \begin{lstlisting}[language=C++] 105 | int main() 106 | { 107 | // クロージャーオブジェクトを代入するための変数 108 | std::function< int() > f ; 109 | 110 | { 111 | X x ; // xが構築される 112 | f = x.get_closure_object() ; 113 | // xが破棄される 114 | } 115 | 116 | // すでにxは破棄された 117 | // return &x->dataで破棄されたxを参照する 118 | std::cout << f() << std::endl ; 119 | } 120 | \end{lstlisting} 121 | 122 | なんと、すでに破棄されたオブジェクトへのリファレンスを参照してしまっている。これは未定義の動作だ。 123 | 124 | 初期化ラムダキャプチャーを使えば、非\lstinline!static!データメンバーもコピーキャプチャーできる。 125 | 126 | \begin{lstlisting}[language=C++] 127 | auto get_closure_object() 128 | { 129 | return [data=data]{ return data ; } ; 130 | } 131 | \end{lstlisting} 132 | 133 | なお、ムーブキャプチャーは存在しない。ムーブというのは特殊なコピーなので初期化ラムダキャプチャーがあれば実現できるからだ。 134 | \index{むぶきやぷちや@ムーブキャプチャー} 135 | 136 | \begin{lstlisting}[language=C++] 137 | auto f() 138 | { 139 | std::string str ; 140 | std::cin >> str ; 141 | // ムーブ 142 | return [str = std::move(str)]{ return str ; } ; 143 | } 144 | \end{lstlisting} 145 | 146 | 機能テストマクロは~\lstinline!__cpp_init_captures!, 値は201304。 147 | \index{\_\_cpp\_init\_captures@\texttt{\_\_cpp\_init\_captures}} 148 | -------------------------------------------------------------------------------- /AsciiDWANGO/010-cpp14-core-variable-template.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 2.8 3 | \hypersection{section2-8}{変数テンプレート} 4 | 5 | 変数テンプレートとは変数宣言をテンプレート宣言にできる機能だ。 6 | \index{へんすうてんぷれと@変数テンプレート}\index{てんぷれとせんげん@テンプレート宣言} 7 | 8 | \begin{lstlisting}[language=C++] 9 | template < typename T > 10 | T variable { } ; 11 | 12 | int main() 13 | { 14 | variable = 42 ; 15 | variable = 1.0 ; 16 | } 17 | \end{lstlisting} 18 | 19 | これだけではわからないだろうから、順を追って説明する。 20 | 21 | C++ではクラスを宣言できる。 22 | \index{くらすせんげん@クラス宣言} 23 | 24 | \begin{lstlisting}[language=C++] 25 | class X 26 | { 27 | int member ; 28 | } ; 29 | \end{lstlisting} 30 | 31 | C++ではクラスをテンプレート宣言できる。型テンプレートパラメーターは型として使える。 32 | \index{てんぷれとせんげん@テンプレート宣言} 33 | 34 | \begin{lstlisting}[language=C++] 35 | template < typename T > 36 | class X 37 | { 38 | public : 39 | T member ; 40 | } ; 41 | 42 | int main() 43 | { 44 | X i ; 45 | i.member = 42 ; // int 46 | 47 | X d ; 48 | d.member = 1.0 ; // double 49 | } 50 | \end{lstlisting} 51 | 52 | C++では関数を宣言できる。 53 | \index{かんすうせんげん@関数宣言} 54 | 55 | \begin{lstlisting}[language=C++] 56 | int f( int x ) 57 | { return x ; } 58 | \end{lstlisting} 59 | 60 | C++では関数をテンプレート宣言できる。型テンプレートパラメーターは型として使える。 61 | \index{てんぷれとせんげん@テンプレート宣言} 62 | 63 | \begin{lstlisting}[language=C++] 64 | template < typename T > 65 | T f( T x ) 66 | { return x ; } 67 | 68 | int main() 69 | { 70 | auto i = f( 42 ) ; // int 71 | auto d = f( 1.0 ) ; // double 72 | } 73 | \end{lstlisting} 74 | 75 | C++11では\lstinline!typedef!名を宣言するためにエイリアス宣言ができる。 76 | \index{typedefめい@\texttt{typedef名}}\index{えいりあすせんげん@エイリアス宣言} 77 | 78 | \begin{lstlisting}[language=C++] 79 | using type = int ; 80 | \end{lstlisting} 81 | 82 | C++11ではエイリアス宣言をテンプレート宣言できる。型テンプレートパラメーターは型として使える。 83 | \index{てんぷれとせんげん@テンプレート宣言} 84 | 85 | \begin{lstlisting}[language=C++] 86 | template < typename T > 87 | using type = T ; 88 | 89 | int main() 90 | { 91 | type i = 42 ; // int 92 | type d = 1.0 ; // double 93 | } 94 | \end{lstlisting} 95 | 96 | そろそろパターンが見えてきたのではないだろうか。C++では一部の宣言はテンプレート宣言できるということだ。このパターンを踏まえて以下を考えてみよう。 97 | 98 | C++では変数を宣言できる。 99 | \index{へんすうせんげん@変数宣言} 100 | 101 | \begin{lstlisting}[language=C++] 102 | int variable{} ; 103 | \end{lstlisting} 104 | 105 | C++14では変数宣言をテンプレート宣言できる。型テンプレートパラメーターは型として使える。 106 | \index{てんぷれとせんげん@テンプレート宣言} 107 | 108 | \begin{lstlisting}[language=C++] 109 | template < typename T > 110 | T variable { } ; 111 | 112 | int main() 113 | { 114 | variable = 42 ; 115 | variable = 1.0 ; 116 | } 117 | \end{lstlisting} 118 | 119 | 変数テンプレートは名前どおり変数宣言をテンプレート宣言できる機能だ。変数テンプレートはテンプレート宣言なので、名前空間スコープとクラススコープの中にしか書くことができない。 120 | 121 | \begin{lstlisting}[language=C++] 122 | // これはグローバル名前空間スコープという特別な名前空間スコープ 123 | 124 | namespace ns { 125 | // 名前空間スコープ 126 | } 127 | 128 | class 129 | { 130 | // クラススコープ 131 | } ; 132 | \end{lstlisting} 133 | 134 | 変数テンプレートの使い道は主に2つある。 135 | 136 | % 137 | % SubSection 2.8.1 138 | \hypersubsection{section2-8-1}{意味は同じだが型が違う定数} 139 | \index{かたがちがうていすう@型が違う定数}\index{ていすう@定数!かたがちがう@型が違う〜} 140 | 141 | プログラムでマジックナンバーを変数化しておくのは良い作法であるとされている。たとえば円周率を\lstinline!3.14...!などと書くよりも\lstinline!pi!という変数名で扱ったほうがわかりやすい。変数化すると、円周率の値が後で変わったときにプログラムを変更するのも楽になる。 142 | \index{まじつくなんば@マジックナンバー} 143 | 144 | \begin{lstlisting}[language=C++] 145 | constexpr double pi = 3.1415926535 ; 146 | \end{lstlisting} 147 | 148 | しかし、円周率を表現する型が複数ある場合どうすればいいのか。よくあるのは名前を分ける方法だ。 149 | 150 | \begin{lstlisting}[language=C++] 151 | constexpr float pi_f = 3.1415 ; 152 | constexpr double pi_d = 3.1415926535 ; 153 | constexpr int pi_i = 3 ; 154 | // 任意の精度の実数を表現できるクラスとする 155 | const Real pi_r("3.141592653589793238462643383279") ; 156 | \end{lstlisting} 157 | 158 | しかしこれは、使う側で型によって名前を変えなければならない。 159 | 160 | \begin{lstlisting}[language=C++] 161 | // 円の面積を計算する関数 162 | template < typename T > 163 | T calc_area( T r ) 164 | { 165 | // Tの型によって使うべき名前が変わる 166 | return r * r * ??? ; 167 | } 168 | \end{lstlisting} 169 | 170 | 関数テンプレートを使うという手がある。 171 | \index{かんすうてんぷれと@関数テンプレート} 172 | 173 | \begin{lstlisting}[language=C++] 174 | template < typename T > 175 | constexpr T pi() 176 | { 177 | return static_cast(3.1415926535) ; 178 | } 179 | 180 | template < > 181 | Real pi() 182 | { 183 | return Real("3.141592653589793238462643383279") ; 184 | } 185 | 186 | 187 | template < typename T > 188 | T calc_area( T r ) 189 | { 190 | return r * r * pi() ; 191 | } 192 | \end{lstlisting} 193 | 194 | しかし、この場合引数は何もないのに関数呼び出しのための\lstinline!()!が必要だ。 195 | 196 | 変数テンプレートを使うと以下のように書ける。 197 | \index{へんすうてんぷれと@変数テンプレート} 198 | 199 | \begin{lstlisting}[language=C++] 200 | template < typename T > 201 | constexpr T pi = static_cast(3.1415926535) ; 202 | 203 | template < > 204 | Real pi("3.141592653589793238462643383279") ; 205 | 206 | template < typename T > 207 | T calc_area( T r ) 208 | { 209 | return r * r * pi ; 210 | } 211 | \end{lstlisting} 212 | 213 | 214 | % 215 | % SubSection 2.8.2 216 | \hypersubsection{section2-8-2}{traitsのラッパー} 217 | 218 | 値を返す\lstinline!traits!で値を得るには~\lstinline!::value!~と書かなければならない。 219 | \index{traits@\texttt{traits}}\index{::value@\texttt{::value}} 220 | 221 | \begin{lstlisting}[language=C++] 222 | std::is_pointer::value ; 223 | std::is_same< int, int >::value ; 224 | \end{lstlisting} 225 | 226 | C++14では\lstinline!std::integral_constant!に\lstinline!constexpr operator bool!が追加されたので、以下のようにも書ける。 227 | \index{std::integral\_constant@\texttt{std::integral\_constant}} 228 | 229 | \begin{lstlisting}[language=C++] 230 | std::is_pointer{} ; 231 | std::is_same< int, int >{} ; 232 | \end{lstlisting} 233 | 234 | しかしまだ面倒だ。変数テンプレートを使うと\lstinline!traits!の記述が楽になる。 235 | 236 | \begin{lstlisting}[language=C++] 237 | template < typename T > 238 | constexpr bool is_pointer_v = std::is_pointer::value ; 239 | template < typename T, typename U > 240 | constexpr bool is_same_v = std::is_same::value ; 241 | 242 | is_pointer_v ; 243 | is_same_v< int, int > ; 244 | \end{lstlisting} 245 | 246 | C++の標準ライブラリでは従来の\lstinline!traits!ライブラリを変数テンプレートでラップした~\lstinline!_v!~版を用意している。 247 | \index{\_vばん@\texttt{\_v}版} 248 | 249 | 機能テストマクロは~\lstinline!__cpp_variable_templates!, 値は201304。 250 | \index{\_\_cpp\_variable\_templates@\texttt{\_\_cpp\_variable\_templates}} 251 | -------------------------------------------------------------------------------- /AsciiDWANGO/011-cpp14-core-constexpr.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 2.9 3 | \hypersection{section2-9}{constexpr関数の制限緩和} 4 | 5 | C++11で追加された\lstinline!constexpr!関数はとても制限が強い。\lstinline!constexpr!関数の本体には実質\lstinline!return!文1つしか書けない。 6 | \index{constexpr@\texttt{constexpr}} 7 | 8 | C++14では、ほとんど何でも書けるようになった。 9 | 10 | \begin{lstlisting}[language=C++] 11 | constexpr int f( int x ) 12 | { 13 | // 変数を宣言できる 14 | int sum = 0 ; 15 | 16 | // 繰り返し文を書ける 17 | for ( int i = 1 ; i < x ; ++i ) 18 | { 19 | // 変数を変更できる 20 | sum += i ; 21 | } 22 | 23 | return sum ; 24 | } 25 | \end{lstlisting} 26 | 27 | 機能テストマクロは~\lstinline!__cpp_constexpr!, 値は201304。 28 | \index{\_\_cpp\_constexpr@\texttt{\_\_cpp\_constexpr}} 29 | 30 | C++11の\lstinline!constexpr!関数に対応しているがC++14の\lstinline!constexpr!関数に対応していないC++実装では、\lstinline!__cpp_constexpr!マクロの値は200704になる。 31 | -------------------------------------------------------------------------------- /AsciiDWANGO/012-cpp14-core-member-initializer-list-init.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 2.10 3 | \hypersection{section2-10}{メンバー初期化子とアグリゲート初期化の組み合わせ} 4 | 5 | C++14ではメンバー初期化子とアグリゲート初期化が組み合わせられるようになった。 6 | \index{めんばしよきかし@メンバー初期化子}\index{あぐりげとしよきかし@アグリゲート初期化} 7 | 8 | メンバー初期化子とはクラスの非\lstinline!static!データメンバーを~\lstinline!=!~で初期化できるC++11の機能だ。 9 | \index{ひstaticでためんば@非\texttt{static}データメンバー} 10 | 11 | \begin{lstlisting}[language=C++] 12 | struct S 13 | { 14 | // メンバー初期化子 15 | int data = 123 ; 16 | } ; 17 | \end{lstlisting} 18 | 19 | アグリゲート初期化とはアグリゲートの条件を満たす型をリスト初期化で初期化できるC++11の機能だ。 20 | 21 | \begin{lstlisting}[language=C++] 22 | struct S 23 | { 24 | int x, y, z ; 25 | } ; 26 | 27 | S s = { 1,2,3 } ; 28 | // s.x == 1, s.y == 2, s.z == 3 29 | \end{lstlisting} 30 | 31 | C++11ではメンバー初期化子を持つクラスはアグリゲート型の条件を満たさないのでアグリゲート初期化ができない。 32 | 33 | C++14では、この制限が緩和された。 34 | 35 | \begin{lstlisting}[language=C++] 36 | struct S 37 | { 38 | int x, y=1, z ; 39 | } ; 40 | 41 | S s1 = { 1 } ; 42 | // s1.x == 1, s1.y == 1, s1.z == 0 43 | 44 | S s2{ 1,2,3 } ; 45 | // s2.x == 1, s2.y == 2, s2.z == 3 46 | \end{lstlisting} 47 | 48 | アグリゲート初期化で、メンバー初期化子を持つ非\lstinline!static!データメンバーに対応する値がある場合はアグリゲート初期化が優先される。省略された場合はメンバー初期化子で初期化される。アグリゲート初期化でもメンバー初期化子でも明示的に初期化されていない非\lstinline!static!データメンバーは空の初期化リストで初期化された場合と同じになる。 49 | 50 | 機能テストマクロは~\lstinline!__cpp_aggregate_nsdmi!, 値は201304。 51 | \index{\_\_cpp\_aggregate\_nsdmi@\texttt{\_\_cpp\_aggregate\_nsdmi}} 52 | -------------------------------------------------------------------------------- /AsciiDWANGO/013-cpp14-core-sized-deallocation.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 2.11 3 | \hypersection{section2-11}{サイズ付き解放関数} 4 | \index{さいずつきかいほうかんすう@サイズ付き解放関数} 5 | 6 | C++14では\lstinline!operator delete!のオーバーロードに、解放すべきストレージのサイズを取得できるオーバーロードが追加された。 7 | \index{operator delete@\texttt{operator delete}}\index{delete@\texttt{delete}} 8 | 9 | \begin{lstlisting}[language=C++] 10 | void operator delete ( void *, std::size_t ) noexcept ; 11 | void operator delete[] ( void *, std::size_t ) noexcept ; 12 | \end{lstlisting} 13 | 14 | 第二引数は\lstinline!std::size_t!型で、第一引数で指定されたポインターが指す解放すべきストレージのサイズが与えられる。 15 | \index{std::size\_t@\texttt{std::size\_t}} 16 | 17 | たとえば以下のように使える。 18 | 19 | \begin{lstlisting}[language=C++] 20 | void * operator new ( std::size_t size ) 21 | { 22 | void * ptr = std::malloc( size ) ; 23 | 24 | if ( ptr == nullptr ) 25 | throw std::bad_alloc() ; 26 | 27 | std::cout << "allocated storage of size: " << size << '\n' ; 28 | return ptr ; 29 | } 30 | 31 | void operator delete ( void * ptr, std::size_t size ) noexcept 32 | { 33 | std::cout << "deallocated storage of size: " << size << '\n' ; 34 | std::free( ptr ) ; 35 | } 36 | 37 | int main() 38 | { 39 | auto u1 = std::make_unique(0) ; 40 | auto u2 = std::make_unique(0.0) ; 41 | } 42 | \end{lstlisting} 43 | 44 | 機能テストマクロは~\lstinline!__cpp_sized_deallocation!, 値は201309。 45 | \index{\_\_cpp\_sized\_deallocation@\texttt{\_\_cpp\_sized\_deallocation}} 46 | -------------------------------------------------------------------------------- /AsciiDWANGO/014-cpp17-core.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Chapter 3 3 | \hyperchapter{chapter3}{C++17のコア言語の新機能}{C++17のコア言語の新機能} 4 | 5 | C++14の新機能のおさらいが終わったところで、いよいよC++17のコア言語の新機能を解説していく。 6 | \index{C++17}\index{C++17!こあげんご@コア言語} 7 | 8 | C++17のコア言語の新機能には、C++11ほどの大きなものはない。 9 | -------------------------------------------------------------------------------- /AsciiDWANGO/015-cpp17-core-remove-trigraph.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.1 3 | \hypersection{section3-1}{トライグラフの廃止} 4 | 5 | C++17ではトライグラフが廃止された。 6 | \index{とらいぐらふ@トライグラフ} 7 | 8 | トライグラフを知らない読者はこの変更を気にする必要はない。トライグラフを知っている読者はなおさら気にする必要はない。 9 | -------------------------------------------------------------------------------- /AsciiDWANGO/016-cpp17-core-hex-float.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.2 3 | \hypersection{section3-2}{16進数浮動小数点数リテラル} 4 | 5 | C++17では浮動小数点数リテラルに16進数を使うことができるようになった。 6 | \index{ふどうしようすうてんすうりてらる@浮動小数点数リテラル}\index{16しんすうふどうしようすうてんすうりてらる@16進数浮動小数点数リテラル} 7 | 8 | 16進数浮動小数点数リテラルは、プレフィクス\lstinline!0x!に続いて仮数部を16進数(\lstinline!0123456789abcdefABCDEF!)で書き、\lstinline!p!もしくは\lstinline!P!に続けて指数部を10進数で書く。 9 | \index{0x@\texttt{0x}} 10 | 11 | \begin{lstlisting}[language=C++] 12 | double d1 = 0x1p0 ; // 1 13 | double d2 = 0x1.0p0 ; // 1 14 | double d3 = 0x10p0 ; // 16 15 | double d4 = 0xabcp0 ; // 2748 16 | \end{lstlisting} 17 | 18 | 指数部は\lstinline!e!ではなく\lstinline!p!か\lstinline!P!を使う。 19 | 20 | \begin{lstlisting}[language=C++] 21 | double d1 = 0x1p0 ; 22 | double d2 = 0x1P0 ; 23 | \end{lstlisting} 24 | 25 | 16進数浮動小数点数リテラルでは、指数部を省略できない。 26 | 27 | \begin{lstlisting}[language=C++] 28 | int a = 0x1 ; // 整数リテラル 29 | 0x1.0 ; // エラー、指数部がない 30 | \end{lstlisting} 31 | 32 | 指数部は10進数で記述する。16進数浮動小数点数リテラルは仮数部に2の指数部乗を掛けた値になる。つまり、 33 | \begin{lstlisting}[language=C++] 34 | 0xNpM 35 | \end{lstlisting} 36 | という浮動小数点数リテラルの値は 37 | \[ 38 | N \times 2^M 39 | \] 40 | となる。 41 | 42 | \begin{lstlisting}[language=C++] 43 | 0x1p0 ; // 1 44 | 0x1p1 ; // 2 45 | 0x1p2 ; // 4 46 | 0x10p0 ; // 16 47 | 0x10p1 ; // 32 48 | 0x1p-1 ; // 0.5 49 | 0x1p-2 ; // 0.25 50 | \end{lstlisting} 51 | 52 | 16進数浮動小数点数リテラルには浮動小数点数サフィックスを記述できる。 53 | \index{ふどうしようすうてんすうさふいつくす@浮動小数点数サフィックス} 54 | 55 | \begin{lstlisting}[language=C++] 56 | auto a = 0x1p0f ; // float 57 | auto b = 0x1p0l ; // long double 58 | \end{lstlisting} 59 | 60 | 16進数浮動小数点数リテラルは、浮動小数点数が表現方法の詳細を知っている環境(たとえばIEEE--754)で、正確な浮動小数点数の表現が記述できるようになる。 61 | 62 | 機能テストマクロは~\lstinline!__cpp_hex_float!, 値は201603。 63 | \index{\_\_cpp\_hex\_float@\texttt{\_\_cpp\_hex\_float}} 64 | -------------------------------------------------------------------------------- /AsciiDWANGO/017-cpp17-core-u8-character-literals.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.3 3 | \hypersection{section3-3}{UTF-8文字リテラル} 4 | 5 | C++17ではUTF-8文字リテラルが追加された。 6 | \index{UTF-8もじりてらる@UTF-8文字リテラル} 7 | 8 | \begin{lstlisting}[language=C++] 9 | char c = u8'a' ; 10 | \end{lstlisting} 11 | 12 | UTF-8文字リテラルは文字リテラルにプレフィクス\lstinline!u8!を付ける。UTF-8文字リテラルはUTF-8のコード単位1つで表現できる文字を扱うことができる。UCSの規格としては、C0制御文字と基本ラテン文字Unicodeブロックが該当する。UTF-8文字リテラルに書かれた文字が複数のUTF-8コード単位を必要とする場合はエラーとなる。 13 | \index{u8@\texttt{u8}} 14 | 15 | \begin{lstlisting}[language=C++] 16 | // エラー 17 | // U+3042はUTF-8は0xE3, 0x81, 0x82という3つのコード単位で表現する必要が 18 | // あるため 19 | u8'あ' ; 20 | \end{lstlisting} 21 | 22 | 機能テストマクロはない。 23 | -------------------------------------------------------------------------------- /AsciiDWANGO/018-cpp17-core-noexcept-function-type.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.4 3 | \hypersection{section3-4}{関数型としての例外指定} 4 | 5 | C++17では例外指定が関数型に組み込まれた。 6 | \index{れいがいしてい@例外指定}\index{かんすうがたれいがいしてい@関数型(例外指定)} 7 | 8 | 例外指定とは\lstinline!noexcept!のことだ。\lstinline!noexcept!と\lstinline!noexcept(true)!が指定された関数は例外を外に投げない。 9 | \index{noexcept@\texttt{noexcept}} 10 | 11 | C++14ではこの例外指定は型システムに入っていなかった。そのため、無例外指定の付いた関数へのポインター型は型システムで無例外を保証することができなかった。 12 | 13 | \begin{lstlisting}[language=C++] 14 | // C++14のコード 15 | void f() 16 | { 17 | throw 0 ; 18 | } 19 | 20 | int main() 21 | { 22 | // 無例外指定の付いたポインター 23 | void (*p)() noexcept = &f ; 24 | 25 | // 無例外指定があるにもかかわらず例外を投げる 26 | p() ; 27 | } 28 | \end{lstlisting} 29 | 30 | C++17では例外指定が型システムに組み込まれた。例外指定のある関数型を例外指定のない関数へのポインター型に変換することはできる。逆はできない。 31 | 32 | \begin{lstlisting}[language=C++] 33 | // 型はvoid() 34 | void f() { } 35 | // 型はvoid() noexcept 36 | void g() noexcept { } 37 | 38 | // OK 39 | // p1, &fは例外指定のない関数へのポインター型 40 | void (*p1)() = &f ; 41 | // OK 42 | // 例外指定のある関数へのポインター型&gを例外指定のない関数へのポインター型p2 43 | // に変換できる 44 | void (*p2)() = &g ; // OK 45 | 46 | // エラー 47 | // 例外指定のない関数へのポインター型&fは例外指定のある関数へのポインター型p3 48 | // に変換できない 49 | void (*p3)() noexcept = &f ; 50 | 51 | // OK 52 | // p4, &gは例外指定のある関数へのポインター型 53 | void (*p4)() noexcept = &g ; 54 | \end{lstlisting} 55 | 56 | 機能テストマクロは~\lstinline!__cpp_noexcept_function_type!, 値は201510。 57 | \index{\_\_cpp\_noexcept\_function\_type@\texttt{\_\_cpp\_noexcept\_function\_type}} 58 | -------------------------------------------------------------------------------- /AsciiDWANGO/019-cpp17-core-fold-expressions.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.5 3 | \hypersection{section3-5}{fold式} 4 | 5 | C++17には\lstinline!fold!式が入った。\lstinline!fold!は元は数学の概念で畳み込みとも呼ばれている。 6 | \index{foldしき@\texttt{fold}式}\index{たたみこみ@畳み込み} 7 | 8 | C++における\lstinline!fold!式とはパラメーターパックの中身に二項演算子を適用するための式だ。 9 | \index{ぱらめたぱつく@パラメーターパック} 10 | 11 | 今、可変長テンプレートを使って受け取った値をすべて加算した合計を返す関数\lstinline!sum!を書きたいとする。 12 | \index{かへんちようてんぷれと@可変長テンプレート} 13 | 14 | \begin{lstlisting}[language=C++] 15 | template < typename T, typename ... Types > 16 | auto sum( T x, Types ... args ) ; 17 | 18 | int main() 19 | { 20 | int result = sum(1,2,3,4,5,6,7,8,9) ; // 45 21 | } 22 | \end{lstlisting} 23 | 24 | このような関数テンプレート\lstinline!sum!は以下のように実装することができる。 25 | 26 | \begin{lstlisting}[language=C++] 27 | template < typename T > 28 | auto sum( T x ) 29 | { 30 | return x ; 31 | } 32 | 33 | template < typename T, typename ... Types > 34 | auto sum( T x, Types ... args ) 35 | { 36 | return x + sum( args... ) ; 37 | } 38 | \end{lstlisting} 39 | 40 | \lstinline!sum(x, args)!は1番目の引数を\lstinline!x!で、残りをパラメーターパック\lstinline!args!で受け取る。そして、\lstinline!x + sum( args ... )!を返す。すると、\lstinline!sum( args ... )!はまた\lstinline!sum(x, args)!に渡されて、1番目の引数、つまり最初から見て2番目の引数が\lstinline!x!に入り、また\lstinline!sum!が呼ばれる。このような再帰的な処理を繰り返していく。 41 | 42 | そして、引数が1つだけになると、可変長テンプレートではない\lstinline!sum!が呼ばれる。これは重要だ。なぜならば可変長テンプレートは0個の引数を取ることができるので、そのまま可変長テンプレート版の\lstinline!sum!が呼ばれてしまうと、次の\lstinline!sum!の呼び出しができずにエラーとなる。これを回避するために、また再帰の終了条件のために、引数が1つの\lstinline!sum!のオーバーロード関数を書いておく。 43 | 44 | 可変長テンプレートでは任意個の引数に対応するために、このような再帰的なコードが必須になる。 45 | 46 | しかし、ここで実現したいこととは\(N\)個あるパラメーターパック\lstinline!args!の中身に対して、仮に\(N\)番目を\lstinline!args#N!とする表記を使うと、\lstinline!args#0! 47 | + \lstinline!args#1! + \ldots{} + 48 | \lstinline!args#N-1!のような展開をしたいだけだ。C++17の\lstinline!fold!式はパラメーターパックに対して二項演算子を適用する展開を行う機能だ。 49 | 50 | \lstinline!fold!式を使うと\lstinline!sum!は以下のように書ける。 51 | 52 | \begin{lstlisting}[language=C++] 53 | template < typename ... Types > 54 | auto sum( Types ... args ) 55 | { 56 | return ( ... + args ) ; 57 | } 58 | \end{lstlisting} 59 | 60 | \lstinline!( ... + args )!は、\lstinline!args#0! + \lstinline!args#1! + 61 | \ldots{} + \lstinline!args#N-1!のように展開される。 62 | 63 | \lstinline!fold!式には、単項\lstinline!fold!式と二項\lstinline!fold!式がある。そして、演算子の結合順序に合わせて左\lstinline!fold!と右\lstinline!fold!がある。 64 | \index{たんこうfoldしき@単項\texttt{fold}式}\index{にこうfoldしき@二項\texttt{fold}式}\index{foldしき@\texttt{fold}式!たんこうfoldしき@単項〜}\index{foldしき@\texttt{fold}式!にこうfoldしき@二項〜}\index{ひだりfold@左\texttt{fold}}\index{みぎfold@右\texttt{fold}}\index{foldしき@\texttt{fold}式!ひだりfold@左〜}\index{foldしき@\texttt{fold}式!みぎfold@右〜} 65 | 66 | \lstinline!fold!式は必ず括弧で囲まなければならない。 67 | 68 | \begin{lstlisting}[language=C++] 69 | template < typename ... Types > 70 | auto sum( Types ... args ) 71 | { 72 | // fold式 73 | ( ... + args ) ; 74 | // エラー、括弧がない 75 | ... + args ; 76 | } 77 | \end{lstlisting} 78 | 79 | 単項\lstinline!fold!式の文法は以下のいずれかになる。 80 | \index{たんこうfoldしき@単項\texttt{fold}式}\index{foldしき@\texttt{fold}式!たんこうfoldしき@単項〜} 81 | 82 | \begin{lstlisting} 83 | 単項右fold 84 | ( cast-expression fold-operator ... ) 85 | 単項左fold 86 | ( ... fold-operator cast-expression ) 87 | \end{lstlisting} 88 | 89 | \noindent 90 | \textsf{例}: 91 | 92 | \begin{lstlisting}[language=C++] 93 | template < typename ... Types > 94 | void f( Types ... args ) 95 | { 96 | // 単項左fold 97 | ( ... + args ) ; 98 | // 単項右fold 99 | ( args + ... ) ; 100 | } 101 | \end{lstlisting} 102 | 103 | \lstinline!cast-expression!には未展開のパラメーターパックが入っていなければならない。 104 | 105 | \vskip 1zw 106 | \noindent 107 | \textsf{例}: 108 | 109 | \begin{lstlisting}[language=C++] 110 | template < typename T > 111 | T f( T x ) { return x ; } 112 | 113 | template < typename ... Types > 114 | auto g( Types ... args ) 115 | { 116 | // f(args#0) + f(args#1) + ... + f(args#N-1) 117 | return ( ... + f(args) ) ; 118 | } 119 | \end{lstlisting} 120 | 121 | これは\lstinline!f(args)!というパターンが展開される。 122 | 123 | \lstinline!fold-operator!には以下のいずれかの二項演算子を使うことができる。 124 | 125 | \begin{lstlisting} 126 | + - * / % ^ & | << >> 127 | += -= *= /= %= ^= &= |= <<= >>= 128 | == != < > <= >= && || , .* ->* 129 | \end{lstlisting} 130 | 131 | \lstinline!fold!式には左\lstinline!fold!と右\lstinline!fold!がある。 132 | \index{ひだりfold@左\texttt{fold}}\index{みぎfold@右\texttt{fold}}\index{foldしき@\texttt{fold}式!ひだりfold@左〜}\index{foldしき@\texttt{fold}式!みぎfold@右〜} 133 | 134 | 左\lstinline!fold!式の\lstinline!( ... op pack )!では、展開結果は\lstinline[breaklines=true]!((( pack#0 op pack#1 ) op pack#2 ) ... op pack#N-1 )!となる。右\lstinline!fold!式の\lstinline!( pack op ... )!では、展開結果は\lstinline[breaklines=true]!( pack#0 op ( pack#1 op ( pack#2 op ( ... op pack#N-1 ))))!となる。 135 | 136 | \begin{lstlisting}[language=C++] 137 | template < typename ... Types > 138 | void sum( Types ... args ) 139 | { 140 | // 左fold 141 | // ((((1+2)+3)+4)+5) 142 | auto left = ( ... + args ) ; 143 | // 右fold 144 | // (1+(2+(3+(4+5)))) 145 | auto right = ( args + ... ) ; 146 | } 147 | 148 | int main() 149 | { 150 | sum(1,2,3,4,5) ; 151 | } 152 | \end{lstlisting} 153 | 154 | 浮動小数点数のような交換法則を満たさない型に\lstinline!fold!式を適用する際には注意が必要だ。 155 | 156 | 二項\lstinline!fold!式の文法は以下のいずれかになる。 157 | \index{にこうfoldしき@二項\texttt{fold}式}\index{foldしき@\texttt{fold}式!にこうfoldしき@二項〜} 158 | 159 | \begin{lstlisting}[language=C++] 160 | ( cast-expression fold-operator ... fold-operator cast-expression ) 161 | \end{lstlisting} 162 | 163 | 左右の\lstinline!cast-expression!のどちらか片方だけに未展開のパラメーターパックが入っていなければならない。2つの\lstinline!fold-operator!は同じ演算子でなければならない。 164 | 165 | \lstinline!( e1 op1 ... op2 e2 )!という二項\lstinline!fold!式があったとき、\lstinline!e1!にパラメーターパックがある場合は二項右\lstinline!fold!式、\lstinline!e2!にパラメーターパックがある場合は二項左\lstinline!fold!式になる。 166 | 167 | \begin{lstlisting}[language=C++] 168 | template < typename ... Types > 169 | void sum( Types ... args ) 170 | { 171 | // 左fold 172 | // (((((0+1)+2)+3)+4)+5) 173 | auto left = ( 0 + ... + args ) ; 174 | // 右fold 175 | // (1+(2+(3+(4+(5+0))))) 176 | auto right = ( args + ... + 0 ) ; 177 | } 178 | 179 | int main() 180 | { 181 | sum(1,2,3,4,5) ; 182 | } 183 | \end{lstlisting} 184 | 185 | \lstinline!fold!式はパラメーターパックのそれぞれに二項演算子を適用したいときにわざわざ複雑な再帰的テンプレートを書かずにすむ方法を提供してくれる。 186 | 187 | 機能テストマクロは~\lstinline!__cpp_fold_expressions!, 値は201603。 188 | \index{\_\_cpp\_fold\_expressions@\texttt{\_\_cpp\_fold\_expressions}} 189 | -------------------------------------------------------------------------------- /AsciiDWANGO/020-cpp17-core-capture-this-by-value.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.6 3 | \hypersection{section3-6}{ラムダ式で~*this~のコピーキャプチャー} 4 | 5 | C++17ではラムダ式で~\lstinline!*this!~をコピーキャプチャーできるようになった。\lstinline!*this!~をコピーキャプチャーするには、ラムダキャプチャーに~\lstinline!*this!~と書く。 6 | \index{らむだしき@ラムダ式}\index{*this@\texttt{*this}}\index{こぴきやぷちや@コピーキャプチャー} 7 | 8 | \begin{lstlisting}[language=C++] 9 | struct X 10 | { 11 | int data = 42 ; 12 | auto get() 13 | { 14 | return [*this]() { return this->data ; } ; 15 | } 16 | } ; 17 | 18 | int main() 19 | { 20 | std::function < int () > f ; 21 | { 22 | X x ; 23 | f = x.get() ; 24 | }// xの寿命はここまで 25 | 26 | // コピーされているので問題ない 27 | int data = f() ; 28 | } 29 | \end{lstlisting} 30 | 31 | コピーキャプチャーする~\lstinline!*this!~はラムダ式が書かれた場所の~\lstinline!*this!~だ。 32 | 33 | また、以下のようなコードで挙動の違いを見るとわかりやすい。 34 | 35 | \begin{lstlisting}[language=C++] 36 | struct X 37 | { 38 | int data = 0 ; 39 | void f() 40 | { 41 | // thisはポインターのキャプチャー 42 | // dataはthisポインターをたどる 43 | [this]{ data = 1 ; }() ; 44 | 45 | // this->dataは1 46 | 47 | // エラー、*thisはコピーされている 48 | // クロージャーオブジェクトのコピーキャプチャーされた変数は 49 | // デフォルトで変更できない 50 | [*this]{ data = 2 ; } () ; 51 | 52 | // OK、mutableを使っている 53 | 54 | [*this]() mutable { data = 2 ; } () ; 55 | 56 | // this->dataは1 57 | // 変更されたのはコピーされたクロージャーオブジェクト内の*this 58 | } 59 | } ; 60 | \end{lstlisting} 61 | 62 | 最初のラムダ式で生成されるクロージャーオブジェクトは以下のようなものだ。 63 | 64 | \begin{lstlisting}[language=C++] 65 | class closure_object 66 | { 67 | X * this_ptr ; 68 | 69 | public : 70 | closure_object( X * this_ptr ) 71 | : this_ptr(this_ptr) { } 72 | 73 | void operator () () const 74 | { 75 | this_ptr->data = 1 ; 76 | } 77 | } ; 78 | \end{lstlisting} 79 | 80 | 2番目のラムダ式では以下のようなクロージャーオブジェクトが生成される。 81 | 82 | \begin{lstlisting}[language=C++] 83 | class closure_object 84 | { 85 | X this_obj ; 86 | X const * this_ptr = &this_obj ; 87 | 88 | public : 89 | closure_object( X const & this_obj ) 90 | : this_obj(this_obj) { } 91 | 92 | void operator () () const 93 | { 94 | this_ptr->data = 2 ; 95 | } 96 | } ; 97 | \end{lstlisting} 98 | 99 | これはC++の文法に従っていないのでやや苦しいコード例だが、コピーキャプチャーされた値を変更しようとしているためエラーとなる。 100 | 101 | 3番目のラムダ式では以下のようなクロージャーオブジェクトが生成される。 102 | 103 | \begin{lstlisting}[language=C++] 104 | class closure_object 105 | { 106 | X this_obj ; 107 | X * this_ptr = &this_obj ; 108 | 109 | public : 110 | closure_object( X const & this_obj ) 111 | : this_obj(this_obj) { } 112 | 113 | void operator () () 114 | { 115 | this_ptr->data = 2 ; 116 | } 117 | } ; 118 | \end{lstlisting} 119 | 120 | ラムダ式に\lstinline!mutable!が付いているのでコピーキャプチャーされた値も変更できる。 121 | \index{mutable@\texttt{mutable}} 122 | 123 | \lstinline!*this!をコピーキャプチャーした場合、\lstinline!this!キーワードはコピーされたオブジェクトへのポインターになる。 124 | 125 | \begin{lstlisting}[language=C++] 126 | struct X 127 | { 128 | int data = 42 ; 129 | void f() 130 | { 131 | // thisはこのメンバー関数fを呼び出したオブジェクトへのアドレス 132 | std::printf("%p\n", this) ; 133 | 134 | // thisはコピーされた別のオブジェクトへのアドレス 135 | [*this](){ std::printf("%p\n", this) ; }() ; 136 | } 137 | } ; 138 | 139 | int main() 140 | { 141 | X x ; 142 | x.f() ; 143 | } 144 | \end{lstlisting} 145 | 146 | この場合、出力される2つのポインターの値は異なる。 147 | 148 | ラムダ式での~\lstinline!*this!~のコピーキャプチャーは名前どおり~\lstinline!*this!~のコピーキャプチャーを提供する提案だ。同等の機能は初期化キャプチャーでも可能だが、表記が冗長で間違いの元だ。 149 | 150 | \begin{lstlisting}[language=C++] 151 | struct X 152 | { 153 | int data ; 154 | 155 | auto f() 156 | { 157 | return [ tmp = *this ] { return tmp.data ; } ; 158 | } 159 | } ; 160 | \end{lstlisting} 161 | 162 | 機能テストマクロは~\lstinline!__cpp_capture_star_this!, 値は201603。 163 | \index{\_\_cpp\_capture\_star\_this@\texttt{\_\_cpp\_capture\_star\_this}} 164 | -------------------------------------------------------------------------------- /AsciiDWANGO/021-cpp17-core-constexpr-lambda.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.7 3 | \hypersection{section3-7}{constexprラムダ式} 4 | 5 | C++17ではラムダ式が\lstinline!constexpr!になった。より正確に説明すると、ラムダ式のクロージャーオブジェクトの\lstinline!operator ()!は条件を満たす場合\lstinline!constexpr!になる。 6 | \index{らむだしき@ラムダ式}\index{constexpr@\texttt{constexpr}}\index{くろじやおぶじえくと@クロージャーオブジェクト}\index{operator ()@\texttt{operator ()}} 7 | 8 | \begin{lstlisting}[language=C++] 9 | int main() 10 | { 11 | auto f = []{ return 42 ; } ; 12 | 13 | constexpr int value = f() ; // OK 14 | } 15 | \end{lstlisting} 16 | 17 | \lstinline!constexpr!の条件を満たすラムダ式はコンパイル時定数を必要とする場所で使うことができる。たとえば\lstinline!constexpr!変数や配列の添字や\lstinline!static_assert!などだ。 18 | 19 | \begin{lstlisting}[language=C++] 20 | int main() 21 | { 22 | auto f = []{ return 42 ; } ; 23 | 24 | int a[f()] ; 25 | static_assert( f() == 42 ) ; 26 | std::array b ; 27 | } 28 | \end{lstlisting} 29 | 30 | \lstinline!constexpr!の条件を満たすのであれば、キャプチャーもできる。 31 | 32 | \begin{lstlisting}[language=C++] 33 | int main() 34 | { 35 | int a = 0 ; // 実行時の値 36 | constexpr int b = 0 ; // コンパイル時定数 37 | 38 | auto f = [=]{ return a ; } ; 39 | auto g = [=]{ return b ; } ; 40 | 41 | // エラー、constexprの条件を満たさない 42 | constexpr int c = f() ; 43 | 44 | // OK、constexprの条件を満たす 45 | constexpr int d = g() ; 46 | } 47 | \end{lstlisting} 48 | 49 | 以下の内容は上級者向けの解説であり、通常の読者は理解する必要がない。 50 | 51 | \lstinline!constexpr!ラムダ式はSFINAEの文脈で使うことができない。 52 | \index{SFINAE} 53 | 54 | \begin{lstlisting}[language=C++] 55 | // エラー 56 | template < typename T, 57 | bool b = []{ 58 | T t ; 59 | t.func() ; 60 | return true ; 61 | }() ; > 62 | void f() 63 | { 64 | T t ; 65 | t.func() ; 66 | } 67 | \end{lstlisting} 68 | 69 | なぜならば、これを許してしまうとテンプレート仮引数に対して任意の式や文がテンプレートのSubstitutionに失敗するかどうかをチェックできてしまうからだ。 70 | 71 | 上級者向けの解説終わり。 72 | 73 | 機能テストマクロは~\lstinline!__cpp_constexpr!, 値は201603。 74 | \index{\_\_cpp\_constexpr@\texttt{\_\_cpp\_constexpr}} 75 | 76 | \lstinline!__cpp_constexpr!マクロの値は、C++11の時点で200704、C++14の時点で201304だ。 77 | -------------------------------------------------------------------------------- /AsciiDWANGO/022-cpp17-core-static-assert.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.8 3 | \hypersection{section3-8}{文字列なしstatic\texttt{\_}assert} 4 | \index{もじれつなしstatic\_assert@文字列なし\texttt{static\_assert}}\index{static\_assert@\texttt{static\_assert}!もじれつなし@文字列なし} 5 | 6 | C++17では\lstinline!static_assert!に文字列リテラルを取らないものが追加された。 7 | 8 | \begin{lstlisting}[language=C++] 9 | static_assert( true ) ; 10 | \end{lstlisting} 11 | 12 | C++11で追加された\lstinline!static_assert!には、文字列リテラルが必須だった。 13 | 14 | \begin{lstlisting}[language=C++] 15 | static_assert( true, "this shall not be asserted." ) ; 16 | \end{lstlisting} 17 | 18 | 特に文字列を指定する必要がない場合もあるので、文字列リテラルを取らない\lstinline!static_assert!が追加された。 19 | 20 | 機能テストマクロは~\lstinline!__cpp_static_assert!, 値は201411。 21 | \index{\_\_cpp\_static\_assert@\texttt{\_\_cpp\_static\_assert}} 22 | 23 | C++11の時点で~\lstinline!__cpp_static_assert!の値は200410。 24 | -------------------------------------------------------------------------------- /AsciiDWANGO/023-cpp17-core-nested-namespace-definition.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.9 3 | \hypersection{section3-9}{ネストされた名前空間定義} 4 | 5 | C++17ではネストされた名前空間の定義を楽に書ける。 6 | \index{ねすとされたなまえくうかん@ネストされた名前空間}\index{なまえくうかん@名前空間!ねすとされた@ネストされた〜} 7 | 8 | ネストされた名前空間とは、\lstinline!A::B::C!のように名前空間の中に名前空間が入っている名前空間のことだ。 9 | 10 | \begin{lstlisting}[language=C++] 11 | namespace A { 12 | namespace B { 13 | namespace C { 14 | // ... 15 | } 16 | } 17 | } 18 | \end{lstlisting} 19 | 20 | C++17では、上記のコードと同じことを以下のように書ける。 21 | 22 | \begin{lstlisting}[language=C++] 23 | namespace A::B::C { 24 | // ... 25 | } 26 | \end{lstlisting} 27 | 28 | 機能テストマクロは~\lstinline!__cpp_nested_namespace_definitions!, 29 | 値は201411。 30 | \index{\_\_cpp\_nested\_namespace\_definitions@\texttt{\_\_cpp\_nested\_namespace\_definitions}} 31 | -------------------------------------------------------------------------------- /AsciiDWANGO/024-cpp17-core-fallthrough-attribute.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.10 3 | \hypersection{section3-10}{{[}{[}fallthrough{]}{]}属性} 4 | 5 | \lstinline![[fallthrough]]!属性は\lstinline!switch!文の中の\lstinline!case!ラベルを突き抜けるというヒントを出すのに使える。 6 | \index{[[fallthrough]]ぞくせい@\texttt{[[fallthrough]]}属性} 7 | 8 | \lstinline!switch!文では対応する\lstinline!case!ラベルに処理が移る。通常、以下のように書く。 9 | 10 | \begin{lstlisting}[language=C++] 11 | void f( int x ) 12 | { 13 | switch ( x ) 14 | { 15 | case 0 : 16 | // 処理0 17 | break ; 18 | case 1 : 19 | // 処理1 20 | break ; 21 | case 2 : 22 | // 処理2 23 | break ; 24 | default : 25 | // xがいずれでもない場合の処理 26 | break ; 27 | } 28 | } 29 | \end{lstlisting} 30 | 31 | この例を以下のように書くと 32 | \begin{lstlisting}[language=C++] 33 | case 1 : 34 | // 処理1 35 | case 2 : 36 | // 処理2 37 | break ; 38 | \end{lstlisting} 39 | \lstinline!x!が1のときは処理1を実行した後に、処理2も実行される。\lstinline!switch!文を書くときはこのような誤りを書いてしまうことがある。そのため、賢いC++コンパイラーは\lstinline!switch!文の\lstinline!case!ラベルで\lstinline!break!文や\lstinline!return!文などで処理が終わらず、次の\lstinline!case!ラベルや\lstinline!default!ラベルに処理に突き抜けるコードを発見すると、警告メッセージを出す。 40 | 41 | しかし、プログラマーの意図がまさに突き抜けて処理してほしい場合、警告メッセージは誤った警告となってしまう。そのような警告メッセージを抑制するため、またコード中に処理が突き抜けるという意図をわかりやすく記述するために、\lstinline![[fallthrough]]!属性が追加された。 42 | 43 | \begin{lstlisting}[language=C++] 44 | case 1 : 45 | // 処理1 46 | [[fallthrough]] 47 | case 2 : 48 | // 処理2 49 | break ; 50 | \end{lstlisting} 51 | 52 | \lstinline![[fallthrough]]!属性を書くと、C++コンパイラーは処理がその先に突き抜けることがわかるので、誤った警告メッセージを抑制できる。また、他人がコードを読むときに意図が明らかになる。 53 | 54 | 機能テストマクロは~\lstinline!__has_cpp_attribute(fallthrough)!, 55 | 値は201603。 56 | \index{\_\_has\_cpp\_attribute(fallthrough)@\texttt{\_\_has\_cpp\_attribute(fallthrough)}} 57 | -------------------------------------------------------------------------------- /AsciiDWANGO/025-cpp17-core-nodiscard-attribute.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.11 3 | \hypersection{section3-11}{{[}{[}nodiscard{]}{]}属性} 4 | 5 | \lstinline![[nodiscard]]!属性は関数の戻り値が無視されてほしくないときに使うことができる。\lstinline![[nodiscard]]!属性が付与された関数の戻り値を無視すると警告メッセージが表示される。 6 | \index{[[nodiscard]]ぞくせい@\texttt{[[nodiscard]]}属性} 7 | 8 | \begin{lstlisting}[language=C++] 9 | [[nodiscard]] int f() 10 | { 11 | return 0 ; 12 | } 13 | 14 | void g( int ) { } 15 | 16 | int main() 17 | { 18 | // エラー、戻り値が無視されている 19 | f() ; 20 | 21 | // OK、戻り値は無視されていない 22 | int result = f() ; 23 | g( f ) ; 24 | f() + 1 ; 25 | (void) f() ; 26 | } 27 | \end{lstlisting} 28 | 29 | 戻り値を無視する、というのは万能ではない。上の例でも、意味的には戻り値は無視されていると言えるが、コンパイラーはこの場合に戻り値が無視されているとは考えない。 30 | 31 | \lstinline![[nodiscard]]!の目的は、戻り値を無視してほしくない関数をユーザーが利用したときの初歩的な間違いを防ぐためにある。\lstinline!void!型にキャストするような意図的な戻り値の無視まで防ぐようには作られていない。 32 | 33 | \lstinline![[nodiscard]]!属性を使うべき関数は、戻り値を無視してほしくない関数だ。どのような関数が戻り値を無視してほしくないかというと大きく2つある。 34 | 35 | 戻り値をエラーなどのユーザーが確認しなければならない情報の通知に使う関数。 36 | 37 | \begin{lstlisting}[language=C++] 38 | enum struct error_code 39 | { 40 | no_error, some_operations_failed, serious_error 41 | } ; 42 | 43 | // 失敗するかもしれない処理 44 | error_code do_something_that_may_fail() 45 | { 46 | // 処理 47 | 48 | if ( is_error_condition() ) 49 | return error_code::serious_error ; 50 | 51 | // 処理 52 | 53 | return error_code::no_error ; 54 | } 55 | 56 | // エラーがいっさい発生しなかったときの処理 57 | int do_something_on_no_error() ; 58 | 59 | int main() 60 | { 61 | // エラーを確認していない 62 | do_something_that_may_fail() ; 63 | 64 | // エラーがない前提で次の処理をしようとする 65 | do_something_on_no_error() ; 66 | } 67 | \end{lstlisting} 68 | 69 | 関数に\lstinline![[nodiscard]]!属性を付与しておけば、このようなユーザー側の初歩的なエラー確認の欠如に警告メッセージを出せる。 70 | 71 | \lstinline![[nodiscard]]!属性は、クラスと\lstinline!enum!にも付与することができる。 72 | 73 | \begin{lstlisting}[language=C++] 74 | class [[nodiscard]] X { } ; 75 | enum class [[nodiscard]] Y { } ; 76 | \end{lstlisting} 77 | 78 | \lstinline![[nodiscard]]!が付与されたクラスか\lstinline!enum!が戻り値の型である関数は\lstinline![[nodiscard]]!が付与された扱いとなる。 79 | 80 | \begin{lstlisting}[language=C++] 81 | class [[nodiscard]] X { } ; 82 | 83 | X f() { return X{} ; } 84 | 85 | int main() 86 | { 87 | // 警告、戻り値が無視されている 88 | f() ; 89 | } 90 | \end{lstlisting} 91 | 92 | 機能テストマクロは~\lstinline!__has_cpp_attribute(nodiscard)!, 93 | 値は201603。 94 | \index{\_\_has\_cpp\_attribute(nodiscard)@\texttt{\_\_has\_cpp\_attribute(nodiscard)}} 95 | -------------------------------------------------------------------------------- /AsciiDWANGO/026-cpp17-core-maybe_unused-attribute.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.12 3 | \hypersection{section3-12}{{[}{[}maybe\texttt{\_}unused{]}{]}属性} 4 | 5 | \lstinline![[maybe_unused]]!属性は名前やエンティティが意図的に使われないことを示すのに使える。 6 | \index{[[maybe\_unused]]ぞくせい@\texttt{[[maybe\_unused]]}属性} 7 | 8 | 現実のC++のコードでは、宣言されているのにソースコードだけを考慮するとどこからも使われていないように見える名前やエンティティが存在する。 9 | 10 | \begin{lstlisting}[language=C++] 11 | void do_something( int *, int * ) ; 12 | 13 | void f() 14 | { 15 | int x[5] ; 16 | char reserved[1024] = { } ; 17 | int y[5] ; 18 | 19 | do_something( x, y ) ; 20 | } 21 | \end{lstlisting} 22 | 23 | ここでは\lstinline!reserved!という名前はどこからも使われていない。一見すると不必要な名前に見える。優秀なC++コンパイラーはこのようなどこからも使われていない名前に対して「どこからも使われていない」という警告メッセージを出す。 24 | 25 | しかし、コンパイラーから見えているソースコードがプログラムのすべてではない。さまざまな理由で\lstinline!reserved!のような一見使われていない変数が必要になる。 26 | 27 | たとえば、\lstinline!reserved!はスタック破壊を検出するための領域かもしれない。プログラムはC++以外の言語で書かれたコードとリンクしていて、そこで使われるのかもしれない。あるいはOSや外部デバイスが読み書きするメモリーとして確保しているのかもしれない。 28 | 29 | どのような理由にせよ、名前やエンティティが一見使われていないように見えるが存在が必要であるという意味を表すのに、\lstinline![[maybe_unused]]!属性を使うことができる。これにより、C++コンパイラーの「未使用の名前」という警告メッセージを抑制できる。 30 | 31 | \begin{lstlisting}[language=C++] 32 | [[maybe_unused]] char reserved[1024] ; 33 | \end{lstlisting} 34 | 35 | \lstinline![[maybe_unused]]!属性を適用できる名前とエンティティの宣言は、クラス、\lstinline!typedef!名、変数、非\lstinline!static!データメンバー、関数、\lstinline!enum!, 36 | \lstinline!enumerator!だ。 37 | 38 | \begin{lstlisting}[language=C++] 39 | // クラス 40 | class [[maybe_unused]] class_name 41 | { 42 | // 非staticデータメンバー 43 | [[maybe_unused]] int non_static_data_member ; 44 | 45 | } ; 46 | 47 | // typedef名 48 | // どちらでもよい 49 | [[maybe_unused]] typedef int typedef_name1 ; 50 | typedef int typedef_name2 [[maybe_unused]] ; 51 | 52 | // エイリアス宣言によるtypedef名 53 | using typedef_name3 [[maybe_unused]] = int ; 54 | 55 | // 変数 56 | // どちらでもよい 57 | [[maybe_unused]] int variable_name1{}; 58 | int variable_name2 [[maybe_unused]] { } ; 59 | 60 | // 関数 61 | // メンバー関数も同じ文法 62 | // どちらでもよい 63 | [[maybe_unused]] void function_name1() { } 64 | void function_name2 [[maybe_unused]] () { } 65 | 66 | enum [[maybe_unused]] enum_name 67 | { 68 | // enumerator 69 | enumerator_name [[maybe_unused]] = 0 70 | } ; 71 | \end{lstlisting} 72 | 73 | 機能テストマクロは~\lstinline!__has_cpp_attribute(maybe_unused)!, 74 | 値は201603 75 | \index{\_\_has\_cpp\_attribute(maybe\_unused)@\texttt{\_\_has\_cpp\_attribute(maybe\_unused)}} 76 | -------------------------------------------------------------------------------- /AsciiDWANGO/027-cpp17-core-evaluation-order.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.13 3 | \hypersection{section3-13}{演算子のオペランドの評価順序の固定} 4 | 5 | C++17では演算子のオペランドの評価順序が固定された。 6 | \index{えんざんしのひようかじゆんじよ@演算子の評価順序} 7 | 8 | 以下の式は、\lstinline!a!, \lstinline!b!の順番に評価されることが規格上保証される。\lstinline!@=!~の~\lstinline!@!~には文法上許される任意の演算子が入る(\lstinline!+=!, \lstinline!-=!~など)。 9 | 10 | \begin{lstlisting}[language=C++] 11 | a.b 12 | a->b 13 | a->*b 14 | a(b1,b2,b3) 15 | b = a 16 | b @= a 17 | a[b] 18 | a << b 19 | a >> b 20 | \end{lstlisting} 21 | 22 | つまり、 23 | \begin{lstlisting}[language=C++] 24 | int* f() ; 25 | int g() ; 26 | 27 | int main() 28 | { 29 | f()[g()] ; 30 | } 31 | \end{lstlisting} 32 | と書いた場合、関数\lstinline!f!がまず先に呼び出されて、次に関数\lstinline!g!が呼び出されることが保証される。 33 | 34 | 関数呼び出しの実引数のオペランド\lstinline!b1!, \lstinline!b2!, 35 | \lstinline!b3!の評価順序は未規定のままだ。 36 | 37 | これにより、既存の未定義の動作となっていたコードの挙動が定まる。 38 | -------------------------------------------------------------------------------- /AsciiDWANGO/029-cpp17-core-selection-statement-with-initializer.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.15 3 | \hypersection{section3-15}{初期化文付き条件文} 4 | 5 | C++17では、条件文に初期化文を記述できるようになった。 6 | \index{しよきかぶんつきじようけんぶん@初期化文付き条件文}\index{じょうけんぶん@条件文!しよきかぶんつき@初期化文付き〜} 7 | 8 | \begin{lstlisting}[language=C++] 9 | if ( int x = 1 ; x ) 10 | /*...*/ ; 11 | 12 | switch( int x = 1 ; x ) 13 | { 14 | case 1 : 15 | /*... */; 16 | } 17 | \end{lstlisting} 18 | 19 | これは、以下のコードと同じ意味になる。 20 | 21 | \begin{lstlisting}[language=C++] 22 | { 23 | int x = 1 ; 24 | if ( x ) ; 25 | } 26 | 27 | { 28 | int x = 1 ; 29 | switch( x ) 30 | { 31 | case 1 : ; 32 | } 33 | } 34 | \end{lstlisting} 35 | 36 | なぜこのような機能が追加されたかというと、変数を宣言し、\lstinline!if!文の条件に変数を使い、\lstinline!if!文を実行後は変数を使用しない、というパターンは現実のコードで頻出するからだ。 37 | 38 | \begin{lstlisting}[language=C++] 39 | void * ptr = std::malloc(10) ; 40 | if ( ptr != nullptr ) 41 | { 42 | // 処理 43 | std::free(ptr) ; 44 | } 45 | // これ以降ptrは使わない 46 | 47 | FILE * file = std::fopen("text.txt", "r") ; 48 | if ( file != nullptr ) 49 | { 50 | // 処理 51 | std::fclose( file ) ; 52 | } 53 | // これ以降fileは使わない 54 | 55 | auto int_ptr = std::make_unique(42) ; 56 | if ( ptr ) 57 | { 58 | // 処理 59 | } 60 | // これ以降int_ptrは使わない 61 | \end{lstlisting} 62 | 63 | 上記のコードには問題がある。これ以降変数は使わないが、変数自体は使えるからだ。 64 | 65 | \begin{lstlisting}[language=C++] 66 | auto ptr = std::make_unique(42) ; 67 | if ( ptr ) 68 | { 69 | // 処理 70 | } 71 | // これ以降ptrは使わない 72 | 73 | // でも使える 74 | int value = *ptr ; 75 | \end{lstlisting} 76 | 77 | 変数を使えないようにするには、ブロックスコープで囲むことで、変数をスコープから外してやればよい。 78 | 79 | \begin{lstlisting}[language=C++] 80 | { 81 | auto int_ptr = std::make_unique(42) ; 82 | if ( ptr ) 83 | { 84 | // 処理 85 | } 86 | // ptrは破棄される 87 | } 88 | // これ以降ptrは使わないし使えない 89 | \end{lstlisting} 90 | 91 | このようなパターンは頻出するので、初期化文付きの条件文が追加された。 92 | 93 | \begin{lstlisting}[language=C++] 94 | if ( auto ptr = std::make_unique(42) ; ptr ) 95 | { 96 | // 処理 97 | } 98 | \end{lstlisting} 99 | 100 | -------------------------------------------------------------------------------- /AsciiDWANGO/030-cpp17-core-deduction-guide.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.16 3 | \hypersection{section3-16}{クラステンプレートのコンストラクターからの実引数推定} 4 | 5 | C++17ではクラステンプレートのコンストラクターの実引数からテンプレート実引数の推定が行えるようになった。 6 | \index{てんぷれとじつひきすうのすいてい@テンプレート実引数の推定} 7 | 8 | \begin{lstlisting}[language=C++] 9 | template < typename T > 10 | struct X 11 | { 12 | X( T t ) { } 13 | } ; 14 | 15 | int main() 16 | { 17 | X x1(0) ; // X 18 | X x2(0.0) ; // X 19 | X x3("hello") ; // X 20 | } 21 | \end{lstlisting} 22 | 23 | これは関数テンプレートが実引数からテンプレート実引数の推定が行えるのと同じだ。 24 | 25 | \begin{lstlisting}[language=C++] 26 | template < typename T > 27 | void f( T t ) { } 28 | 29 | int main() 30 | { 31 | f( 0 ) ; // f 32 | f( 0.0 ) ; // f 33 | f( "hello" ) ; // f 34 | } 35 | \end{lstlisting} 36 | 37 | % 38 | % SubSection 3.16.1 39 | \hypersubsection{section3-16-1}{推定ガイド} 40 | 41 | クラステンプレートのコンストラクターからの実引数は便利だが、クラスのコンストラクターはクラステンプレートのテンプレートパラメーターに一致しない場合もある。そのような場合はそのままでは実引数推定ができない。 42 | \index{すいていがいど@推定ガイド} 43 | 44 | \begin{lstlisting}[language=C++] 45 | // コンテナー風のクラス 46 | template < typename T > 47 | class Container 48 | { 49 | std::vector c ; 50 | public : 51 | // 初期化にイテレーターのペアを取る 52 | // IteratorはTではない 53 | // Tは推定できない 54 | template < typename Iterator > 55 | Container( Iterator first, Iterator last ) 56 | : c( first, last ) 57 | { } 58 | } ; 59 | 60 | 61 | int main() 62 | { 63 | int a[] = { 1,2,3,4,5 } ; 64 | 65 | // エラー 66 | // Tを推定できない 67 | Container c( std::begin(a), std::end(a) ) ; 68 | } 69 | \end{lstlisting} 70 | 71 | このため、C++17には推定ガイドという機能が提供されている。 72 | 73 | \begin{lstlisting}[language=C++] 74 | テンプレート名( 引数リスト ) -> テンプレートid ; 75 | \end{lstlisting} 76 | 77 | これを使うと、以下のように書ける。 78 | 79 | \begin{lstlisting}[language=C++] 80 | template < typename Iterator > 81 | Container( Iterator, Iterator ) 82 | -> Container< typename std::iterator_traits< Iterator >::value_type > ; 83 | \end{lstlisting} 84 | 85 | C++コンパイラーはこの推定ガイドを使って、\lstinline[breaklines=true]!Container::Container(Iterator, Iterator)!からは、\lstinline!T!を\lstinline!std::iterator_traits::value_type!として推定すればいいのだと判断できる。 86 | 87 | たとえば、初期化リストに対応するには以下のように書く。 88 | 89 | \begin{lstlisting}[language=C++] 90 | template < typename T > 91 | class Container 92 | { 93 | std::vector c ; 94 | public : 95 | 96 | Container( std::initializer_list init ) 97 | : c( init ) 98 | { } 99 | } ; 100 | 101 | 102 | template < typename T > 103 | Container( std::initializer_list ) -> Container ; 104 | 105 | 106 | int main() 107 | { 108 | Container c = { 1,2,3,4,5 } ; 109 | } 110 | \end{lstlisting} 111 | 112 | C++コンパイラーはこの推定ガイドから、\lstinline[breaklines=true]!Container::Container( std::initializer_list )!の場合は\lstinline!T!を\lstinline!T!として推定すればよいことがわかる。 113 | 114 | 機能テストマクロは~\lstinline!__cpp_deduction_guides!, 値は201606。 115 | \index{\_\_cpp\_deduction\_guides@\texttt{\_\_cpp\_deduction\_guides}} 116 | -------------------------------------------------------------------------------- /AsciiDWANGO/031-cpp17-core-template-auto.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.17 3 | \hypersection{section3-17}{autoによる非型テンプレートパラメーターの宣言} 4 | 5 | C++17では非型テンプレートパラメーターの宣言に\lstinline!auto!を使うことができるようになった。 6 | \index{ひかたてんぷれとぱらめた@非型テンプレートパラメーター}\index{auto@\texttt{auto}} 7 | 8 | \begin{lstlisting}[language=C++] 9 | template < auto x > 10 | struct X { } ; 11 | 12 | void f() { } 13 | 14 | int main() 15 | { 16 | X<0> x1 ; 17 | X<0l> x2 ; 18 | X<&f> x3 ; 19 | } 20 | \end{lstlisting} 21 | 22 | これはC++14までであれば、以下のように書かなければならなかった。 23 | 24 | \begin{lstlisting}[language=C++] 25 | template < typename T, T x > 26 | struct X { } ; 27 | 28 | void f() { } 29 | 30 | int main() 31 | { 32 | X x1 ; 33 | X x2 ; 34 | X x3 ; 35 | } 36 | \end{lstlisting} 37 | 38 | 機能テストマクロは~\lstinline!__cpp_template_auto!, 値は201606。 39 | \index{\_\_cpp\_template\_auto@\texttt{\_\_cpp\_template\_auto}} 40 | -------------------------------------------------------------------------------- /AsciiDWANGO/032-cpp17-core-using-attribute-namespace.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.18 3 | \hypersection{section3-18}{using属性名前空間} 4 | 5 | C++17では、属性名前空間に\lstinline!using!ディレクティブのような記述ができるようになった。 6 | \index{usingぞくせいなまえくうかん@\texttt{using}属性名前空間} 7 | 8 | \begin{lstlisting}[language=C++] 9 | // [[extension::foo, extension::bar]]と同じ 10 | [[ using extension : foo, bar ]] int x ; 11 | \end{lstlisting} 12 | 13 | 属性トークンには、属性名前空間を付けることができる。これにより、独自拡張の属性トークンの名前の衝突を避けることができる。 14 | \index{ぞくせいとくん@属性トークン}\index{ぞくせいなまえくうかん@属性名前空間} 15 | 16 | たとえば、あるC++コンパイラーには独自拡張として\lstinline!foo!, 17 | \lstinline!bar!という属性トークンがあり、別のC++コンパイラーも同じく独自拡張として\lstinline!foo!, 18 | \lstinline!bar!という属性トークンを持っているが、それぞれ意味が違っている場合、コードの意味も違ってしまう。 19 | 20 | \begin{lstlisting}[language=C++] 21 | [[ foo, bar ]] int x ; 22 | \end{lstlisting} 23 | 24 | このため、C++には属性名前空間という文法が用意されている。注意深いC++コンパイラーは独自拡張の属性トークンには属性名前空間を設定していることだろう。 25 | 26 | \begin{lstlisting}[language=C++] 27 | [[ extension::foo, extension::bar ]] int x ; 28 | \end{lstlisting} 29 | 30 | 問題は、これをいちいち記述するのは面倒だということだ。 31 | 32 | C++17では、\lstinline!using!属性名前空間という機能により、\lstinline!using!ディレクティブのような名前空間の省略が可能になった。文法は\lstinline!using!ディレクティブと似ていて、属性の中で\lstinline!using name : ...!と書くことで、コロンに続く属性トークンに、属性名前空間\lstinline!name!を付けたものと同じ効果が得られる。 33 | -------------------------------------------------------------------------------- /AsciiDWANGO/033-cpp17-core-ignore-non-standard-attributes.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.19 3 | \hypersection{section3-19}{非標準属性の無視} 4 | 5 | C++17では、非標準の属性トークンは無視される。 6 | \index{ひひようじゆんぞくせい@非標準属性} 7 | 8 | \begin{lstlisting}[language=C++] 9 | // OK、無視される 10 | [[ wefapiaofeaofjaopfij ]] int x ; 11 | \end{lstlisting} 12 | 13 | 属性はC++コンパイラーによる独自拡張をC++の規格に準拠する形で穏便に追加するための機能だ。その属性のためにコンパイルエラーになった場合、けっきょくCプリプロセッサーを使うか、わずらわしさから独自の文法が使われてしまう。そのためこの機能は必須だ。 14 | -------------------------------------------------------------------------------- /AsciiDWANGO/035-cpp17-core-inline-variables.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.21 3 | \hypersection{section3-21}{inline変数} 4 | 5 | C++17では変数に\lstinline!inline!キーワードを指定できるようになった。 6 | \index{inline@\texttt{inline}!へんすう@変数} 7 | 8 | \begin{lstlisting}[language=C++] 9 | inline int variable ; 10 | \end{lstlisting} 11 | 12 | このような変数を\lstinline!inline!変数と呼ぶ。その意味は\lstinline!inline!関数と同じだ。 13 | \index{inline@\texttt{inline}!かんすう@関数} 14 | 15 | % 16 | % SubSection 3.21.1 17 | \hypersubsection{section3-21-1}{inlineの歴史的な意味} 18 | \index{inline@\texttt{inline}!きわど@キーワード} 19 | 20 | 今は昔、本書執筆から30年以上は昔に、\lstinline!inline!キーワードがC++に追加された。 21 | 22 | \lstinline!inline!の現在の意味は誤解されている。 23 | 24 | \lstinline!inline!関数の意味は、「関数を強制的にインライン展開させるための機能」\textsf{ではない}。 25 | \index{inline@\texttt{inline}!てんかい@展開} 26 | 27 | 大事なことなのでもう一度書くが、\lstinline!inline!関数の意味は、「関数を強制的にインライン展開させるための機能」\textbf{ではない}。 28 | 29 | 確かに、かつて\lstinline!inline!関数の意味は、関数を強制的にインライン展開させるための機能だった。 30 | 31 | 関数のインライン展開とは、たとえば以下のようなコードがあったとき、 32 | \begin{lstlisting}[language=C++] 33 | int min( int a, int b ) 34 | { return a < b ? a : b ; } 35 | 36 | int main() 37 | { 38 | int a, b ; 39 | std::cin >> a >> b ; 40 | 41 | // aとbのうち小さい方を選ぶ 42 | int value = min( a, b ) ; 43 | } 44 | \end{lstlisting} 45 | この関数\lstinline!min!は十分に小さく、関数呼び出しのコストは無視できないオーバーヘッドになるため、以下のような最適化が考えられる。 46 | 47 | \begin{lstlisting}[language=C++] 48 | int main() 49 | { 50 | int a, b ; 51 | std::cin >> a >> b ; 52 | 53 | int value = a < b ? a : b ; 54 | } 55 | \end{lstlisting} 56 | 57 | このように関数の中身を展開することを、関数のインライン展開という。 58 | 59 | 人間が関数のインライン展開を手で行うのは面倒だ。それにコードが読みにくい。``\lstinline!min(a,b)!''と``\lstinline!a 31 | struct S : Types ... 32 | { 33 | using Types::operator() ... ; 34 | void operator () ( long ) { } 35 | } ; 36 | 37 | 38 | struct A 39 | { 40 | void operator () ( int ) { } 41 | } ; 42 | 43 | struct B 44 | { 45 | void operator () ( double ) { } 46 | } ; 47 | 48 | int main() 49 | { 50 | S s ; 51 | s(0) ; // A::operator() 52 | s(0L) ; // S::operator() 53 | s(0.0) ; // B::operator() 54 | } 55 | \end{lstlisting} 56 | 57 | 機能テストマクロは~\lstinline!__cpp_variadic_using!, 値は201611。 58 | \index{\_\_cpp\_variadic\_using@\texttt{\_\_cpp\_variadic\_using}} 59 | -------------------------------------------------------------------------------- /AsciiDWANGO/037-cpp17-core-std-byte.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 3.23 3 | \hypersection{section3-23}{std::byte : バイトを表現する型} 4 | \index{std::byte@\texttt{std::byte}}\index{ばいと@バイト}\index{かた@型!ばいと@バイト}\index{かた@型!std::byte@\texttt{std::byte}} 5 | 6 | C++17では、バイトを表現する型が入った。ライブラリでもあるのだがコア言語で特別な型として扱われている。 7 | 8 | バイトとはC++のメモリーモデルにおけるストレージの単位で、C++においてユニークなアドレスが付与される最小単位だ。C++の規格はいまだに1バイトが具体的に何ビットであるのかを規定していない。これは過去にバイトのサイズが8ビットではないアーキテクチャーが存在したためだ。 9 | 10 | バイトのビット数は~\lstinline!!~で定義されているプリプロセッサーマクロ、\lstinline!CHAR_BIT!で知ることができる。 11 | \index{ばいと@バイト!びつとすう@ビット数}\index{CHAR\_BIT@\texttt{CHAR\_BIT}} 12 | 13 | C++17では、1バイトはUTF-8の8ビットの1コード単位をすべて表現できると規定している。 14 | 15 | \lstinline!std::byte!型は、生のバイト列を表すための型として使うことができる。生の1バイトを表すには\lstinline!unsigned char!型が慣習的に使われてきたが、\lstinline!std::byte!型は生の1バイトを表現する型として、新たにC++17で追加された。複数バイトが連続するストレージは、\lstinline!unsigned char!の配列型、もしくは\lstinline!std::byte!の配列型として表現できる。 16 | \index{unsigned char@\texttt{unsigned char}} 17 | 18 | \lstinline!std::byte!型は、\lstinline!!~で以下のように定義されている。 19 | \index{@\texttt{}} 20 | 21 | \begin{lstlisting}[language=C++] 22 | namespace std 23 | { 24 | enum class byte : unsigned char { } ; 25 | } 26 | \end{lstlisting} 27 | 28 | \lstinline!std::byte!はライブラリとして\lstinline!scoped enum!型で定義されている。これにより、他の整数型からの暗黙の型変換が行えない。 29 | \index{scoped enum@\texttt{scoped enum}}\index{かた@型!scoped enum@\texttt{scoped enum}} 30 | 31 | 値\lstinline!0x12!の\lstinline!std::byte!型の変数は以下のように定義できる。 32 | 33 | \begin{lstlisting}[language=C++] 34 | int main() 35 | { 36 | std::byte b{0x12} ; 37 | } 38 | \end{lstlisting} 39 | 40 | \lstinline!std::byte!型の値がほしい場合は、以下のように書くことができる。 41 | 42 | \begin{lstlisting}[language=C++] 43 | int main() 44 | { 45 | std::byte b{} ; 46 | 47 | b = std::byte( 1 ) ; 48 | b = std::byte{ 1 } ; 49 | b = static_cast< std::byte >( 1 ) ; 50 | b = static_cast< std::byte >( 0b11110000 ) ; 51 | } 52 | \end{lstlisting} 53 | 54 | \lstinline!std::byte!型は他の数値型からは暗黙に型変換できない。これによりうっかりと型を取り違えてバイト型と他の型を演算してしまうことを防ぐことができる。 55 | 56 | \begin{lstlisting}[language=C++] 57 | int main() 58 | { 59 | // エラー、()による初期化はint型からの暗黙の変換が入る 60 | std::byte b1(1) ; 61 | 62 | // エラー、=による初期化はint型からの暗黙の変換が入る 63 | std::byte b2 = 1 ; 64 | 65 | std::byte b{} ; 66 | 67 | // エラー、operator =によるint型の代入は暗黙の変換が入る 68 | b = 1 ; 69 | // エラー、operator =によるdouble型の代入は暗黙の変換が入る 70 | b = 1.0 ; 71 | } 72 | \end{lstlisting} 73 | 74 | \lstinline!std::byte!型は~\lstinline!{}!~によって初期化するが、縮小変換を禁止するルールにより、\lstinline!std::byte!型が表現できる値の範囲でなければエラーとなる。 75 | 76 | たとえば、今\lstinline!std::byte!が8ビットで、最小値が0、最大値が255の環境だとする。 77 | 78 | \begin{lstlisting}[language=C++] 79 | int main() 80 | { 81 | // エラー、表現できる値の範囲ではない 82 | std::byte b1{-1} ; 83 | // エラー、表現できる値の範囲ではない 84 | std::byte b2{256} ; 85 | } 86 | \end{lstlisting} 87 | 88 | \lstinline!std::byte!は内部のストレージをバイト単位でアクセスできるようにするため、規格上\lstinline!char!と同じような配慮が行われている。 89 | 90 | \begin{lstlisting}[language=C++] 91 | int main() 92 | { 93 | int x = 42 ; 94 | 95 | std::byte * rep = reinterpret_cast< std::byte * >(&x) ; 96 | } 97 | \end{lstlisting} 98 | 99 | \lstinline!std::byte!は一部の演算子がオーバーロードされているので、通常の整数型のように使うことができる。ただし、バイトをビット列演算するのに使う一部の演算子だけだ。 100 | 101 | 具体的には、以下に示すシフト、ビットOR, ビット列AND, ビット列XOR, 102 | ビット列NOTだ。 103 | 104 | \begin{lstlisting} 105 | <<= << 106 | >>= >> 107 | |= | 108 | &= & 109 | ^= ^ 110 | ~ 111 | \end{lstlisting} 112 | 113 | 四則演算などの演算子はサポートしていない。 114 | 115 | \lstinline!std::byteはstd::to_intenger(std::byte)!により、\lstinline!IntType!型の整数型に変換できる。 116 | \index{IntType@\texttt{IntType}}\index{かた@型!IntType@\texttt{IntType}} 117 | 118 | \begin{lstlisting}[language=C++] 119 | int main() 120 | { 121 | std::byte b{42} ; 122 | 123 | // int型の値は42 124 | auto i = std::to_integer(b) ; 125 | } 126 | \end{lstlisting} 127 | 128 | -------------------------------------------------------------------------------- /AsciiDWANGO/038-cpp17-lib.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Chapter 4 3 | \hyperchapter{chapter4}{C++17の型安全な値を格納するライブラリ}{C++17の型安全な値を\\格納するライブラリ} 4 | 5 | C++17では型安全に値を格納するライブラリとして、\lstinline!variant!, 6 | \lstinline!any!, \lstinline!optional!が追加された。 7 | \index{variant@\texttt{variant}}\index{any@\texttt{any}}\index{optional@\texttt{optional}} 8 | -------------------------------------------------------------------------------- /AsciiDWANGO/046-cpp17-lib-misc.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Chapter 9 3 | \hyperchapter{chapter9}{その他の標準ライブラリ}{その他の標準ライブラリ} 4 | 5 | この章ではC++17で追加された細かいライブラリをまとめて解説する。 6 | -------------------------------------------------------------------------------- /AsciiDWANGO/047-cpp17-lib-misc-hardware-interference-size.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.1 3 | \hypersection{section9-1}{ハードウェア干渉サイズ(キャッシュライン)} 4 | 5 | C++17にはハードウェアの干渉サイズを取得するライブラリが入った。ハードウェアの干渉サイズとは、俗にキャッシュライン(cache 6 | line)とも呼ばれている概念だ。 7 | \index{はどうえあかんしようさいず@ハードウェア干渉サイズ}\index{きやつしゆらいん@キャッシュライン} 8 | 9 | 残念ながら、この2017年では、メモリーは極めて遅い。そのため、プロセッサーはより高速にアクセスできるキャッシュメモリーを用意している。メモリーに対するキャッシュはある程度のまとまったバイト数単位で行われる。この単位が何バイトであるのかは実装依存だ。C++17にはこのサイズを取得できるライブラリが入った。 10 | \index{きやつしゆめもり@キャッシュメモリー} 11 | 12 | ハードウェア干渉サイズを知りたい理由は2つある。2つのオブジェクトを同一の局所性を持つキャッシュに載せたくない場合と載せたい場合だ。 13 | 14 | 2つのオブジェクトのうち、一方は頻繁に変更し、もう一方はめったに変更しない場合で、2つのオブジェクトが同じ局所性を持つキャッシュに載っている場合、よく変更するオブジェクトを変更しただけで、めったに変更しないオブジェクトも、メモリーとの同期が発生する。 15 | 16 | \begin{lstlisting}[language=C++] 17 | struct Data 18 | { 19 | int counter ; 20 | int status ; 21 | } ; 22 | \end{lstlisting} 23 | 24 | ここで、\lstinline!counter!は頻繁に変更するが、\lstinline!status!はめったに変更しない場合、\lstinline!counter!と\lstinline!status!の間に適切なパディングを挿入することで、2つのオブジェクトが同じ局所性を持たないようにしたい。 25 | 26 | この場合には、\lstinline!std::hardware_destructive_interference_size!が使える。 27 | \index{std::hardware\_destructive\_interference\_size@\texttt{std::hardware\_destructive\_interference\_ size}} 28 | 29 | \begin{lstlisting}[language=C++] 30 | struct Data 31 | { 32 | int counter ; 33 | std::byte padding[ 34 | std::hardware_destructive_interference_size - sizeof(int) 35 | ] ; 36 | int status ; 37 | } ; 38 | \end{lstlisting} 39 | 40 | 反対に、2つのオブジェクトを同一の局所性を持つキャッシュに載せたい場合、\lstinline!std::hardware_constructive_interference_size!が使える。 41 | \index{std::hardware\_constructive\_interference\_size@\texttt{std::hardware\_constructive\_interference\_ size}} 42 | 43 | ハードウェア干渉サイズは~\lstinline!!~ヘッダーで以下のように定義されている。 44 | \index{@\texttt{}} 45 | 46 | \begin{lstlisting}[language=C++] 47 | namespace std { 48 | inline constexpr size_t 49 | hardware_destructive_interference_size = 実装依存 ; 50 | inline constexpr size_t 51 | hardware_constructive_interference_size = 実装依存 ; 52 | } 53 | \end{lstlisting} 54 | 55 | -------------------------------------------------------------------------------- /AsciiDWANGO/048-cpp17-misc-uncaught_exceptions.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.2 3 | \hypersection{section9-2}{std::uncaught\texttt{\_}exceptions} 4 | \index{std::uncaught\_exceptions@\texttt{std::uncaught\_exceptions}} 5 | 6 | C++14までは、まだ\lstinline!catch!されていない例外がある場合は、\lstinline[breaklines=true]!bool std::uncaught_exception()!で判定することができた。 7 | \index{std::uncaught\_exception@\texttt{std::uncaught\_exception}} 8 | 9 | \begin{lstlisting}[language=C++] 10 | struct X 11 | { 12 | ~X() 13 | { 14 | if ( std::uncaught_exception() ) 15 | { 16 | // デストラクターはスタックアンワインディング中に呼ばれた 17 | } 18 | else 19 | { 20 | // 通常の破棄 21 | } 22 | } 23 | } ; 24 | 25 | int main() 26 | { 27 | { 28 | X x ; 29 | }// 通常の破棄 30 | 31 | { 32 | X x ; 33 | throw 0 ; 34 | }// スタックアンワインディング中 35 | 36 | } 37 | \end{lstlisting} 38 | 39 | \lstinline!bool std::uncaught_exception()!は、C++17では非推奨扱いになった。いずれ廃止される見込みだ。 40 | 41 | 廃止の理由としては、単に以下のような例で役に立たないからだ。 42 | 43 | \begin{lstlisting}[language=C++] 44 | struct X 45 | { 46 | ~X() 47 | { 48 | try { 49 | // true 50 | bool b = std::uncaught_exception() ; 51 | } catch( ... ) { } 52 | } 53 | } ; 54 | \end{lstlisting} 55 | 56 | このため、\lstinline!int std::uncaught_exceptions()!が新たに追加された。この関数は現在\lstinline!catch!されていない例外の個数を返す。 57 | \index{std::uncaught\_exceptions@\texttt{std::uncaught\_exceptions}} 58 | 59 | \begin{lstlisting}[language=C++] 60 | struct X 61 | { 62 | ~X() 63 | { 64 | try { 65 | if ( int x = std::uncaught_exceptions() ; x > 1 ) 66 | { 67 | // ネストされた例外 68 | } 69 | } catch( ... ) 70 | } 71 | 72 | } ; 73 | \end{lstlisting} 74 | 75 | -------------------------------------------------------------------------------- /AsciiDWANGO/049-cpp17-lib-misc-apply.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.3 3 | \hypersection{section9-3}{apply : tupleの要素を実引数に関数を呼び出す} 4 | 5 | \bgroup 6 | \begin{lstlisting}[language=C++] 7 | template 8 | constexpr decltype(auto) apply(F&& f, Tuple&& t); 9 | \end{lstlisting} 10 | \egroup 11 | 12 | \lstinline!std::apply!は\lstinline!tuple!のそれぞれの要素を順番に実引数に渡して関数を呼び出すヘルパー関数だ。 13 | \index{std::apply@\texttt{std::apply}}\index{tuple@\texttt{tuple}} 14 | 15 | ある要素数\lstinline!N!の\lstinline!tuple t!と関数オブジェクト\lstinline!f!に対して、\lstinline!apply( f, t )!は、\lstinline!f( get<0>(t), get<1>(t), ... , get(t) )!のように\lstinline!f!を関数呼び出しする。 16 | 17 | \vskip 1zw 18 | \noindent 19 | \textsf{例}: 20 | 21 | \begin{lstlisting}[language=C++] 22 | template < typename ... Types > 23 | void f( Types ... args ) { } 24 | 25 | int main() 26 | { 27 | // int, int, int 28 | std::tuple t1( 1,2,3 ) ; 29 | 30 | // f( 1, 2, 3 )の関数呼び出し 31 | std::apply( f, t1 ) ; 32 | 33 | // int, double, const char * 34 | std::tuple t2( 123, 4.56, "hello" ) ; 35 | 36 | // f( 123, 4.56, "hello" )の関数呼び出し 37 | std::apply( f, t2 ) ; 38 | } 39 | \end{lstlisting} 40 | 41 | -------------------------------------------------------------------------------- /AsciiDWANGO/052-cpp17-lib-misc-shared-ptr-for-array.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.6 3 | \hypersection{section9-6}{shared\texttt{\_}ptr\texttt{<}T{[}{]}\texttt{>} : 配列に対するshared\texttt{\_}ptr} 4 | 5 | C++17では、\lstinline!shared_ptr!が配列に対応した。 6 | \index{shared\_ptr@\texttt{shared\_ptr}} 7 | 8 | \begin{lstlisting}[language=C++] 9 | int main() 10 | { 11 | // 配列対応のshared_ptr 12 | std::shared_ptr< int [] > ptr( new int[5] ) ; 13 | 14 | // operator []で配列に添字アクセスできる 15 | ptr[0] = 42 ; 16 | 17 | // shared_ptrのデストラクターがdelete[]を呼び出す 18 | } 19 | \end{lstlisting} 20 | 21 | -------------------------------------------------------------------------------- /AsciiDWANGO/053-cpp17-lib-misc-as-const.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.7 3 | \hypersection{section9-7}{as\texttt{\_}const : const性の付与} 4 | 5 | \lstinline!as_const!はヘッダーファイル~\lstinline!!~で定義されている。 6 | \index{as\_const@\texttt{as\_const}}\index{@\texttt{}} 7 | 8 | \begin{lstlisting}[language=C++] 9 | template constexpr add_const_t& as_const(T& t) noexcept 10 | { 11 | return t ; 12 | } 13 | \end{lstlisting} 14 | 15 | \lstinline!as_const!は引数として渡した\lstinline!lvalue!リファレンスを\lstinline!const!な\lstinline!lvalue!リファレンスにキャストする関数だ。\lstinline!const!性を付与する手軽なヘルパー関数として使うことができる。 16 | 17 | \begin{lstlisting}[language=C++] 18 | // 1 19 | template < typename T > 20 | void f( T & ) {} 21 | // 2、こちらを呼び出したい 22 | template < typename T > 23 | void f( T const & ) { } 24 | 25 | int main() 26 | { 27 | int x{} ; 28 | 29 | f(x) ; // 1 30 | 31 | // constを付与する冗長な方法 32 | int const & ref = x ; 33 | f(ref) ; // 2 34 | 35 | // 簡潔 36 | f( std::as_const(x) ) ; // 2 37 | } 38 | \end{lstlisting} 39 | 40 | -------------------------------------------------------------------------------- /AsciiDWANGO/054-cpp17-lib-misc-make-from-tuple.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.8 3 | \hypersection{section9-8}{make\texttt{\_}from\texttt{\_}tuple : tupleの要素を実引数にコンストラクターを呼び出す} 4 | 5 | \lstinline!make_from_tuple!はヘッダーファイル~\lstinline!!~で定義されている。 6 | \index{make\_from\_tuple@\texttt{make\_from\_tuple}}\index{@\texttt{}} 7 | 8 | \begin{lstlisting}[language=C++] 9 | template 10 | constexpr T make_from_tuple(Tuple&& t); 11 | \end{lstlisting} 12 | 13 | \lstinline!apply!は\lstinline!tuple!の要素を実引数に関数を呼び出すライブラリだが、\lstinline!make_from_tuple!は\lstinline!tuple!の要素を実引数にコンストラクターを呼び出すライブラリだ。 14 | \index{tuple@\texttt{tuple}} 15 | 16 | ある型\lstinline!T!と要素数\lstinline!N!の\lstinline!tuple t!に対して、\lstinline!make_from_tuple(t)!は、\lstinline!T!型を\lstinline!T( get<0>(t), get<1>(t), ... , get(t) )!のように構築して、構築した\lstinline!T!型のオブジェクトを返す。 17 | 18 | \begin{lstlisting}[language=C++] 19 | class X 20 | { 21 | template < typename ... Types > 22 | T( Types ... ) { } 23 | } ; 24 | 25 | int main() 26 | { 27 | // int, int, int 28 | std::tuple t1(1,2,3) ; 29 | 30 | // X(1,2,3) 31 | X x1 = std::make_from_tuple( t1 ) 32 | 33 | // int, double, const char * 34 | std::tuple t2( 123, 4.56, "hello" ) ; 35 | 36 | // X(123, 4.56, "hello") 37 | X x2 = std::make_from_tuple( t2 ) ; 38 | } 39 | \end{lstlisting} 40 | 41 | -------------------------------------------------------------------------------- /AsciiDWANGO/055-cpp17-lib-misc-invoke.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.9 3 | \hypersection{section9-9}{invoke : 指定した関数を指定した実引数で呼び出す} 4 | 5 | \lstinline!invoke!はヘッダーファイル~\lstinline!!~で定義されている。 6 | \index{invoke@\texttt{invoke}}\index{@\texttt{}} 7 | 8 | \begin{lstlisting}[language=C++] 9 | template 10 | invoke_result_t invoke(F&& f, Args&&... args) 11 | noexcept(is_nothrow_invocable_v); 12 | \end{lstlisting} 13 | 14 | \lstinline!invoke( f, t1, t2, ... , tN )!は、関数\lstinline!f!を\lstinline!f( a1, a2, ... , aN )!のように呼び出す。 15 | 16 | より正確には、C++標準規格の\lstinline!INVOKE(f, t1, t2, ... , tN)!と同じ規則で呼び出す。これにはさまざまな規則があり、たとえばメンバー関数へのポインターやデータメンバーへのポインター、またその場合に与えるクラスへのオブジェクトがリファレンスかポインターか\lstinline!reference_wrapper!かによっても異なる。その詳細はここでは解説しない。 17 | \index{INVOKE@\texttt{INVOKE}} 18 | 19 | \lstinline!INVOKE!は\lstinline!std::function!や\lstinline!std::bind!でも使われている規則なので、標準ライブラリと同じ挙動ができるようになると覚えておけばよい。 20 | 21 | \vskip 1zw 22 | \noindent 23 | \textsf{例}: 24 | 25 | \begin{lstlisting}[language=C++] 26 | void f( int ) { } 27 | 28 | struct S 29 | { 30 | void f( int ) ; 31 | int data ; 32 | } ; 33 | 34 | int main() 35 | { 36 | // f( 1 ) 37 | std::invoke( f, 1 ) ; 38 | 39 | S s ; 40 | 41 | // (s.*&S::f)(1) 42 | std::invoke( &S::f, s, 1 ) ; 43 | // ((*&s).*&S::f)(1) 44 | std::invoke( &S::f, &s, 1 ) ; 45 | // s.*&S::data 46 | std::invoke( &S::data, s ) ; 47 | } 48 | \end{lstlisting} 49 | 50 | -------------------------------------------------------------------------------- /AsciiDWANGO/056-cpp17-lib-misc-not-fn.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.10 3 | \hypersection{section9-10}{not\texttt{\_}fn : 戻り値の否定ラッパー} 4 | 5 | \lstinline!not_fn!はヘッダーファイル~\lstinline!!~で定義されている。 6 | \index{not\_fn@\texttt{not\_fn}}\index{@\texttt{}} 7 | 8 | \begin{lstlisting}[language=C++] 9 | template unspecified not_fn(F&& f); 10 | \end{lstlisting} 11 | 12 | 関数オブジェクト\lstinline!f!に対して\lstinline!not_fn(f)!を呼び出すと、戻り値として何らかの関数オブジェクトが返ってくる。その関数オブジェクトを呼び出すと、実引数を\lstinline!f!に渡して\lstinline!f!を関数呼び出しして、戻り値を~\lstinline"operator !"~で否定して返す。 13 | 14 | \begin{lstlisting}[language=C++] 15 | int main() 16 | { 17 | 18 | auto r1 = std::not_fn( []{ return true ; } ) ; 19 | 20 | r1() ; // false 21 | 22 | auto r2 = std::not_fn( []( bool b ) { return b ; } ) ; 23 | 24 | r2(true) ; // false 25 | } 26 | \end{lstlisting} 27 | 28 | すでに廃止予定になった\lstinline!not1!, \lstinline!not2!の代替品。 29 | \index{not1@\texttt{not1}}\index{not2@\texttt{not2}} 30 | -------------------------------------------------------------------------------- /AsciiDWANGO/058-cpp17-lib-misc-weak-ptr.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.12 3 | \hypersection{section9-12}{shared\texttt{\_}ptr::weak\texttt{\_}type} 4 | 5 | C++17では\lstinline!shared_ptr!に\lstinline!weak_type!というネストされた型名が追加された。これは\lstinline!shared_ptr!に対する\lstinline!weak_ptr!の\lstinline!typedef!名となっている。 6 | \index{shared\_ptr::weak\_type@\texttt{shared\_ptr::weak\_type}}\index{weak\_type@\texttt{weak\_type}} 7 | 8 | \begin{lstlisting}[language=C++] 9 | namespace std { 10 | 11 | template < typename T > 12 | class shared_ptr 13 | { 14 | using weak_type = weak_ptr ; 15 | } ; 16 | 17 | } 18 | \end{lstlisting} 19 | 20 | \vskip 1zw 21 | \noindent 22 | \textsf{使い方}: 23 | 24 | \begin{lstlisting}[language=C++] 25 | template < typename Shared_ptr > 26 | void f( Shared_ptr sptr ) 27 | { 28 | // C++14 29 | auto wptr1 = std::weak_ptr< 30 | typename Shared_ptr::element_type 31 | >( sptr ) ; 32 | 33 | // C++17 34 | auto wptr2 = typename Shared_ptr::weak_type( sptr ) ; 35 | } 36 | \end{lstlisting} 37 | 38 | -------------------------------------------------------------------------------- /AsciiDWANGO/059-cpp17-lib-misc-void-t.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.13 3 | \hypersection{section9-13}{void\texttt{\_}t} 4 | 5 | ヘッダーファイル~\lstinline!!~で定義されている\lstinline!void_t!は以下のように定義されている。 6 | \index{@\texttt{}}\index{void\_t@\texttt{void\_t}} 7 | 8 | \begin{lstlisting}[language=C++] 9 | namespace std { 10 | 11 | template < class ... > 12 | using void_t = void ; 13 | 14 | } 15 | \end{lstlisting} 16 | 17 | \lstinline!void_t!は任意個の型をテンプレート実引数として受け取る\lstinline!void!型だ。この性質はテンプレートメタプログラミングにおいてとても便利なので、標準ライブラリに追加された。 18 | -------------------------------------------------------------------------------- /AsciiDWANGO/060-cpp17-lib-misc-bool-constant.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.14 3 | \hypersection{section9-14}{bool\texttt{\_}constant} 4 | 5 | ヘッダーファイル~\lstinline!!~に\lstinline!bool_constant!が追加された。 6 | \index{@\texttt{}}\index{bool\_constant@\texttt{bool\_constant}} 7 | 8 | \begin{lstlisting}[language=C++] 9 | template 10 | using bool_constant = integral_constant; 11 | 12 | using true_type = bool_constant; 13 | using false_type = bool_constant; 14 | \end{lstlisting} 15 | 16 | 今まで\lstinline!integral_constant!を使っていた場面で特に\lstinline!bool!だけが必要な場面では、C++17以降は単に\lstinline!std::true_type!か\lstinline!std::false_type!と書くだけでよくなる。 17 | \index{integral\_constant@\texttt{integral\_constant}}\index{std::true\_type@\texttt{std::true\_type}}\index{std::false\_type@\texttt{std::false\_type}} 18 | -------------------------------------------------------------------------------- /AsciiDWANGO/062-cpp17-lib-misc-minimal-incomplete-type-support-for-containers.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.16 3 | \hypersection{section9-16}{コンテナーで不完全型のサポート} 4 | 5 | \noindent 6 | \textsf{注意}:この説明は上級者向けだ。 7 | 8 | C++17では以下のコードが合法になった。このコードの挙動はC++14までは実装依存であった。 9 | 10 | \begin{lstlisting}[language=C++] 11 | struct X 12 | { 13 | std::vector v ; 14 | std::list l ; 15 | std::forward_list f ; 16 | } ; 17 | \end{lstlisting} 18 | 19 | クラスはクラス定義の終了である~\lstinline!}!~を持って完全型となる。クラススコープに注入されたクラス名は、クラス定義の中ではまだ完全型ではない。不完全型をコンテナーの要素型に指定した場合の挙動は、C++14までは規定されていなかった。 20 | \index{かんぜんがた@完全型}\index{ふかんぜんがた@不完全型} 21 | 22 | C++17では、\lstinline!vector!, \lstinline!list!, 23 | \lstinline!forward_list!に限り、要素型に一時的に不完全型を許すようになった。実際にコンテナーを使う際には完全型になっていなければならない。 24 | -------------------------------------------------------------------------------- /AsciiDWANGO/063-cpp17-lib-misc-emplace.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.17 3 | \hypersection{section9-17}{emplaceの戻り値} 4 | \index{emplace@\texttt{emplace}!もどりち@戻り値} 5 | 6 | C++17ではシーケンスコンテナーの\lstinline!emplace_front!/\lstinline!emplace_back!, 7 | \lstinline!queue!と\lstinline!stack!の\lstinline!emplace!が構築した要素へのリファレンスを返すように変更された。 8 | \index{emplace\_front@\texttt{emplace\_front}}\index{emplace\_back@\texttt{emplace\_back}}\index{queue@\texttt{queue}}\index{stack@\texttt{stack}} 9 | 10 | そのため、C++14では以下のように書いていたコードが、 11 | \begin{lstlisting}[language=C++] 12 | int main() 13 | { 14 | std::vector v ; 15 | 16 | v.emplace_back(0) ; // void 17 | int value = v.back() ; 18 | } 19 | \end{lstlisting} 20 | 以下のように書けるようになった。 21 | \begin{lstlisting}[language=C++] 22 | int main() 23 | { 24 | std::vector v ; 25 | 26 | int value = v.emplace_back(0) ; 27 | } 28 | \end{lstlisting} 29 | 30 | -------------------------------------------------------------------------------- /AsciiDWANGO/064-cpp17-lib-misc-map.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.18 3 | \hypersection{section9-18}{mapとunordered\texttt{\_}mapの変更} 4 | 5 | \lstinline!map!と\lstinline!unordered_map!に、\lstinline!try_emplace!と\lstinline!insert_or_assign!という2つのメンバー関数が入った。このメンバー関数は\lstinline!multi_map!と\lstinline!unordered_multi_map!には追加されていない。 6 | \index{map@\texttt{map}}\index{unordered\_map@\texttt{unordered\_map}}\index{multi\_map@\texttt{multi\_map}}\index{unordered\_multi\_map@\texttt{unordered\_multi\_map}} 7 | 8 | % 9 | % SubSection 9.18.1 10 | \hypersubsection{section9-18-1}{try\texttt{\_}emplace} 11 | \index{try\_emplace@\texttt{try\_emplace}} 12 | 13 | \bgroup 14 | \begin{lstlisting}[language=C++] 15 | template 16 | pair 17 | try_emplace(const key_type& k, Args&&... args); 18 | 19 | template 20 | iterator 21 | try_emplace( 22 | const_iterator hint, 23 | const key_type& k, Args&&... args); 24 | \end{lstlisting} 25 | \egroup 26 | 27 | 従来の\lstinline!emplace!は、キーに対応する要素が存在しない場合、要素が\lstinline!args!から\lstinline!emplace!構築されて追加される。もし、キーに対応する要素が存在する場合、要素は追加されない。要素が追加されないとき、\lstinline!args!がムーブされるかどうかは実装定義である。 28 | \index{emplace@\texttt{emplace}} 29 | 30 | \begin{lstlisting}[language=C++] 31 | int main() 32 | { 33 | std::map< int, std::unique_ptr > m ; 34 | 35 | // すでに要素が存在する 36 | m[0] = nullptr ; 37 | 38 | auto ptr = std::make_unique(0) ; 39 | // emplaceは失敗する 40 | auto [iter, is_emplaced] = m.emplace( 0, std::move(ptr) ) ; 41 | 42 | // 結果は実装により異なる 43 | // ptrはムーブされているかもしれない 44 | bool b = ( ptr != nullptr ) ; 45 | } 46 | \end{lstlisting} 47 | 48 | この場合、実際に\lstinline!map!に要素は追加されていないのに、\lstinline!ptr!はムーブされてしまうかもしれない。 49 | 50 | このため、C++17では、要素が追加されなかった場合\lstinline!args!はムーブされないことが保証される\lstinline!try_emplace!が追加された。 51 | 52 | \begin{lstlisting}[language=C++] 53 | int main() 54 | { 55 | std::map< int, std::unique_ptr > m ; 56 | 57 | // すでに要素が存在する 58 | m[0] = nullptr ; 59 | 60 | auto ptr = std::make_unique(0) ; 61 | // emplaceは失敗する 62 | auto [iter, is_emplaced] = m.emplace( 0, std::move(ptr) ) ; 63 | 64 | // trueであることが保証される 65 | // ptrはムーブされていない 66 | bool b = ( ptr != nullptr ) ; 67 | } 68 | \end{lstlisting} 69 | 70 | % 71 | % SubSection 9.18.2 72 | \hypersubsection{section9-18-2}{insert\texttt{\_}or\texttt{\_}assign} 73 | \index{insert\_or\_assign@\texttt{insert\_or\_assign}} 74 | 75 | \bgroup 76 | \begin{lstlisting}[language=C++] 77 | template 78 | pair 79 | insert_or_assign(const key_type& k, M&& obj); 80 | 81 | template 82 | iterator 83 | insert_or_assign( 84 | const_iterator hint, 85 | const key_type& k, M&& obj); 86 | \end{lstlisting} 87 | \egroup 88 | 89 | \lstinline!insert_or_assign!は\lstinline!key!に連想された要素が存在する場合は要素を代入し、存在しない場合は要素を追加する。\lstinline!operator []!との違いは、要素が代入されたか追加されたかが、戻り値の\lstinline!pair!の\lstinline!bool!でわかるということだ。 90 | 91 | \begin{lstlisting}[language=C++] 92 | int main() 93 | { 94 | std::map< int, int > m ; 95 | m[0] = 0 ; 96 | 97 | { 98 | // 代入 99 | // is_insertedはfalse 100 | auto [iter, is_inserted] = m.insert_or_assign( 0, 1 ) ; 101 | } 102 | 103 | { 104 | // 追加 105 | // is_insertedはtrue 106 | auto [iter, is_inserted] = m.insert_or_assign( 1, 1 ) ; 107 | } 108 | } 109 | \end{lstlisting} 110 | 111 | -------------------------------------------------------------------------------- /AsciiDWANGO/066-cpp17-lib-misc-size.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.20 3 | \hypersection{section9-20}{コンテナーアクセス関数} 4 | 5 | ヘッダーファイル~\lstinline!!~に、コンテナーアクセス関数として、フリー関数版の\lstinline!size!, 6 | \lstinline!empty!, 7 | \lstinline!data!が追加された。それぞれ、メンバー関数の\lstinline!size!, 8 | \lstinline!empty!, \lstinline!data!を呼び出す。 9 | \index{@\texttt{}}\index{こんてなあくせすかんすう@コンテナーアクセス関数}\index{size@\texttt{size}}\index{こんてなあくせすかんすう@コンテナーアクセス関数!size@\texttt{size}}\index{empty@\texttt{empty}}\index{こんてなあくせすかんすう@コンテナーアクセス関数!empty@\texttt{empty}}\index{data@\texttt{data}}\index{こんてなあくせすかんすう@コンテナーアクセス関数!data@\texttt{data}} 10 | 11 | \begin{lstlisting}[language=C++] 12 | int main() 13 | { 14 | std::vector v ; 15 | 16 | std::size(v) ; // v.size() 17 | std::empty(v) ; // v.empty() 18 | std::data(v) ; // v.data() 19 | } 20 | \end{lstlisting} 21 | 22 | このフリー関数は配列や~\lstinline!std::initializer_list!~にも使える。 23 | 24 | \begin{lstlisting}[language=C++] 25 | int main() 26 | { 27 | int a[10] ; 28 | 29 | std::size(a) ; // 10 30 | std::empty(a) ; // 常にfalse 31 | std::data(a) ; // a 32 | } 33 | \end{lstlisting} 34 | 35 | -------------------------------------------------------------------------------- /AsciiDWANGO/067-cpp17-lib-misc-clamp.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.21 3 | \hypersection{section9-21}{clamp} 4 | \index{clamp@\texttt{clamp}} 5 | 6 | \bgroup 7 | \begin{lstlisting}[language=C++] 8 | template 9 | constexpr const T& 10 | clamp(const T& v, const T& lo, const T& hi); 11 | template 12 | constexpr const T& 13 | clamp(const T& v, const T& lo, const T& hi, Compare comp); 14 | \end{lstlisting} 15 | \egroup 16 | 17 | ヘッダーファイル~\lstinline!!~に追加された\lstinline!clamp(v, lo, hi)!は値\lstinline!v!が\lstinline!lo!より小さい場合は\lstinline!lo!を、\lstinline!hi!より高い場合は\lstinline!hi!を、それ以外の場合は\lstinline!v!を返す。 18 | \index{@\texttt{}} 19 | 20 | \begin{lstlisting}[language=C++] 21 | int main() 22 | { 23 | std::clamp( 5, 0, 10 ) ; // 5 24 | std::clamp( -5, 0, 10 ) ; // 0 25 | std::clamp( 50, 0, 10 ) ; // 10 26 | } 27 | \end{lstlisting} 28 | 29 | \lstinline!comp!を実引数に取る\lstinline!clamp!は\lstinline!comp!を値の比較に使う 30 | 31 | \lstinline!clamp!には浮動小数点数も使えるが、NaNは渡せない。 32 | -------------------------------------------------------------------------------- /AsciiDWANGO/068-cpp17-lib-misc-hypot.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.22 3 | \hypersection{section9-22}{3次元hypot} 4 | \index{3じげんhypot@3次元\texttt{hypot}}\index{hypot@\texttt{hypot}} 5 | 6 | \bgroup 7 | \begin{lstlisting}[language=C++] 8 | float hypot(float x, float y, float z); 9 | double hypot(double x, double y, double z); 10 | long double hypot(long double x, long double y, long double z); 11 | \end{lstlisting} 12 | \egroup 13 | 14 | ヘッダーファイル~\lstinline!!~に3次元の\lstinline!hypot!が追加された。 15 | \index{@\texttt{}} 16 | 17 | \vskip 1zw 18 | \noindent 19 | \textsf{戻り値}: 20 | \[ 21 | \sqrt{x^2+y^2+z^2} 22 | \] 23 | -------------------------------------------------------------------------------- /AsciiDWANGO/069-cpp17-lib-misc-atomic-is-always-lock-free.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.23 3 | \hypersection{section9-23}{atomic\texttt{<}T\texttt{>}::is\texttt{\_}always\texttt{\_}lock\texttt{\_}free} 4 | \index{is\_always\_lock\_free@\texttt{is\_always\_lock\_free}} 5 | 6 | \bgroup 7 | \begin{lstlisting}[language=C++] 8 | template < typename T > 9 | struct atomic 10 | { 11 | static constexpr bool is_always_lock_free = ... ; 12 | } ; 13 | \end{lstlisting} 14 | \egroup 15 | 16 | C++17で~\lstinline!!~に追加された\lstinline!atomic::is_always_lock_free!は、\lstinline!atomic!~の実装がすべての実行においてロックフリーであるとコンパイル時に保証できる場合、\lstinline!true!になる\lstinline!static constexpr!な\lstinline!bool!型のデータメンバーだ。 17 | \index{@\texttt{}} 18 | 19 | \lstinline!atomic!には、他にも\lstinline!bool!を返すメンバー関数\lstinline!is_lock_free!があるが、これは実行時にロックフリーであるかどうかを判定できる。\lstinline!is_always_lock_free!はコンパイル時にロックフリーであるかどうかを判定できる。 20 | \index{is\_lock\_free@\texttt{is\_lock\_free}} 21 | -------------------------------------------------------------------------------- /AsciiDWANGO/070-cpp17-misc-scoped-lock.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.24 3 | \hypersection{section9-24}{scoped\texttt{\_}lock : 可変長引数lock\texttt{\_}guard} 4 | 5 | \lstinline!std::scoped_lock!クラス~\lstinline!!~は可変長引数版の\lstinline!lock_guard!だ。 6 | \index{std::scoped\_lock@\texttt{std::scoped\_lock}}\index{lock\_guard@\texttt{lock\_guard}} 7 | 8 | \begin{lstlisting}[language=C++] 9 | int main() 10 | { 11 | std::mutex a, b, c, d ; 12 | 13 | { 14 | // a,b,c,dをlockする 15 | std::scoped_lock l( a, b, c, d ) ; 16 | // a,b,c,dをunlockする 17 | } 18 | } 19 | \end{lstlisting} 20 | 21 | \lstinline!std::scoped_lock!のコンストラクターは複数のロックのオブジェクトのリファレンスを取り、それぞれにデッドロックを起こさない方法でメンバー関数\lstinline!lock!を呼び出す。デストラクターはメンバー関数\lstinline!unlock!を呼び出す。 22 | -------------------------------------------------------------------------------- /AsciiDWANGO/071-cpp17-misc-byte.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.25 3 | \hypersection{section9-25}{std::byte} 4 | \index{std::byte@\texttt{std::byte}} 5 | 6 | C++17ではバイトを表現する型として\lstinline!std::byte!がライブラリに追加された。これは、コア言語の一部であり、\hyperref[std.byte]{別項で詳しく解説を行っている}。 7 | -------------------------------------------------------------------------------- /AsciiDWANGO/072-cpp17-lib-misc-gcd-lcm.tex: -------------------------------------------------------------------------------- 1 | % 2 | % Section 9.26 3 | \hypersection{section9-26}{最大公約数(gcd)と最小公倍数(lcm)} 4 | 5 | C++17ではヘッダーファイル~\lstinline!!~に最大公約数(\lstinline!gcd!)と最小公倍数(\lstinline!lcm!)が追加された。 6 | \index{@\texttt{}} 7 | 8 | \begin{lstlisting}[language=C++] 9 | int main() 10 | { 11 | int a, b ; 12 | 13 | while( std::cin >> a >> b ) 14 | { 15 | std::cout 16 | << "gcd: " << gcd(a,b) 17 | << "\nlcm: " << lcm(a,b) << '\n' ; 18 | } 19 | } 20 | \end{lstlisting} 21 | 22 | % 23 | % SubSection 9.26.1 24 | \hypersubsection{section9-26-1}{gcd : 最大公約数} 25 | \index{gcd@\texttt{gcd}}\index{さいだいこうやくすう@最大公約数} 26 | 27 | \bgroup 28 | \begin{lstlisting}[language=C++] 29 | template 30 | constexpr std::common_type_t gcd(M m, N n) 31 | { 32 | if ( n == 0 ) 33 | return m ; 34 | else 35 | return gcd( n, std::abs(m) % std::abs(n) ) ; 36 | } 37 | \end{lstlisting} 38 | \egroup 39 | 40 | \lstinline!gcd(m, n)!は\lstinline!m!と\lstinline!n!がともにゼロの場合ゼロを返す。それ以外の場合、\(|m|\)と\(|n|\)の最大公約数(Greatest 41 | Common Divisor)を返す。 42 | 43 | % 44 | % SubSection 9.26.2 45 | \hypersubsection{section9-26-2}{lcm : 最小公倍数} 46 | \index{lcm@\texttt{lcm}}\index{さいしようこうばいすう@最小公倍数} 47 | 48 | \bgroup 49 | \begin{lstlisting}[language=C++] 50 | template 51 | constexpr std::common_type_t lcm(M m, N n) 52 | { 53 | if ( m == 0 || n == 0 ) 54 | return 0 ; 55 | else 56 | return std::abs(m) / gcd( m, n ) * std::abs(n) ; 57 | } 58 | \end{lstlisting} 59 | \egroup 60 | 61 | \lstinline!lcm(m,n)!は、\lstinline!m!と\lstinline!n!のどちらかがゼロの場合ゼロを返す。それ以外の場合、\(|m|\)と\(|n|\)の最小公倍数(Least 62 | Common Multiple)を返す。 63 | -------------------------------------------------------------------------------- /AsciiDWANGO/asciibook.cls: -------------------------------------------------------------------------------- 1 | \ProvidesClass{asciibook}[2015/01/30] 2 | \LoadClassWithOptions{jsbook} 3 | 4 | 5 | 6 | % 1行の文字数および版面の左右空き調整 7 | \setlength\paperheight{210truemm} 8 | \setlength\paperwidth{148truemm} 9 | \setlength{\textwidth}{38zw} 10 | %% 11 | \setlength{\evensidemargin}{-8.4truemm} 12 | \setlength{\oddsidemargin}{-3truemm} 13 | 14 | % 1ページの行数を設定 15 | \setlength{\textheight}{35\baselineskip} 16 | 17 | % 本文中のヘッダ、フッタ 18 | \def\ps@asciiheadings{% 19 | \def\@oddfoot{\hfil \thepage}% 20 | \def\@evenfoot{\thepage \hfil}% 21 | \def\@evenhead{\small \leftmark \hfil}% UNIXプログラミング環境: \small 22 | \def\@oddhead{\small \hfil \rightmark}% UNIXプログラミング環境: \small 23 | } 24 | 25 | % 前付けのヘッダ、フッタ 26 | \def\ps@frontheadings{% 27 | \def\@oddfoot{\hfil \thepage}% 28 | \def\@evenfoot{\thepage \hfil}% 29 | \def\@evenhead{}% 30 | \def\@oddhead{}% 31 | } 32 | 33 | 34 | % 章トビラのヘッダ、フッタの指定 35 | \makeatletter 36 | \renewcommand{\chapter}{% 37 | \if@openright\cleardoublepage\else\clearpage\fi 38 | \global\@topnum\z@ 39 | \secdef\@chapter\@schapter} 40 | \makeatother 41 | 42 | % ヘッダの空き調整 43 | \addtolength{\topmargin}{-55pt} 44 | \addtolength{\headsep}{10pt} 45 | 46 | % フッタの空き調整 47 | \setlength\footskip{2.5\baselineskip} 48 | \addtolength{\textheight}{\baselineskip} 49 | 50 | % 印刷位置の調整 51 | \advance\hoffset 0.0in 52 | \advance\voffset 0.0in 53 | 54 | % 見出しフォントを太ゴシックにする 55 | %\renewcommand{\headfont}{\sffamily\bfseries} 56 | \renewcommand{\headfont}{\sffamily\bfseries\ebseries} 57 | 58 | % 章見出しの背景にグラフィックを入れる 59 | \makeatletter 60 | \def\@makechapterhead#1{ 61 | \vbox to 0mm{ 62 | \hbox to 0mm{\includegraphics{title.eps}\hss} 63 | \vss 64 | } 65 | \vbox{ 66 | \vskip 10mm 67 | %% {\huge\headfont \@chapapp\thechapter\@chappos} 68 | \hskip 4mm{\Large\headfont \@chapapp\thechapter\@chappos} 69 | \vskip 5mm 70 | {\huge\headfont \parbox{130mm}{#1}} 71 | \vskip 20mm 72 | } 73 | } 74 | 75 | \renewcommand{\section}{% 76 | \if@slide\clearpage\fi 77 | \@startsection{section}{1}{\z@}% 78 | {1.5\Cvs \@plus.5\Cdp \@minus.2\Cdp}%  前アキ 79 | {.5\Cvs \@plus.3\Cdp}% 後アキ 80 | {\normalfont\large\headfont\raggedright}} 81 | \renewcommand{\subsection}{\@startsection{subsection}{2}{\z@}% 82 | {\Cvs \@plus.5\Cdp \@minus.2\Cdp}% 前アキ 83 | % {.5\Cvs \@plus.3\Cdp}% 後アキ 84 | {.1\Cvs \@plus.3\Cdp}% 後アキ 85 | {\normalfont\normalsize\headfont}} 86 | \renewcommand{\subsubsection}{\@startsection{subsubsection}{3}{\z@}% 87 | {\z@}{\z@}% 88 | {\normalfont\normalsize\sffamily\bfseries}} 89 | 90 | \makeatother 91 | 92 | % 索引のスタイル 93 | \def\ps@indexfoot{% 94 | \def\@oddfoot{% 95 | {\hbox to \fullwidth{\hfil \thepage}}}% 96 | \let\@oddhead\@empty 97 | \def\@evenfoot{% 98 | \hss {\hbox to \fullwidth{\thepage \hfil}}}% 99 | \let\@evenhead\@empty} 100 | -------------------------------------------------------------------------------- /AsciiDWANGO/cpp17book_1211.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EzoeRyou/cpp17book/e58d3b22454111cbc67af7c1599f8dd3d3bb163f/AsciiDWANGO/cpp17book_1211.pdf -------------------------------------------------------------------------------- /AsciiDWANGO/fig/title.eps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EzoeRyou/cpp17book/e58d3b22454111cbc67af7c1599f8dd3d3bb163f/AsciiDWANGO/fig/title.eps -------------------------------------------------------------------------------- /AsciiDWANGO/fig/tobira.eps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EzoeRyou/cpp17book/e58d3b22454111cbc67af7c1599f8dd3d3bb163f/AsciiDWANGO/fig/tobira.eps -------------------------------------------------------------------------------- /AsciiDWANGO/indexstyle.ist: -------------------------------------------------------------------------------- 1 | %group_skip "\bigskip" 2 | lethead_flag 1 3 | letter_head 2 4 | symhead_positive "\\bfseries{記号・数字}" 5 | 6 | %lethead_prefix "\n\\hfill{\\bfseries ---" 7 | %lethead_suffix "---}\\hfill\\hfill\\hfill\\hfill\\par\\nobreak" 8 | 9 | lethead_prefix "\n{\\bfseries{\\color[gray]{0.6} ■} " 10 | lethead_suffix "}\\par\\nobreak" 11 | -------------------------------------------------------------------------------- /AsciiDWANGO/okuduke.tex: -------------------------------------------------------------------------------- 1 | \cleardoublepage 2 | 3 | \thispagestyle{empty} 4 | 5 | \begin{spacing}{0.7} 6 | \noindent \textgt{\footnotesize ●本書に対するお問い合わせは、電子メール(\texttt{info@asciidwango.jp})にてお願いいたします。\\ 7 | 但し、本書の記述内容を越えるご質問にはお答えできませんので、ご了承ください。} 8 | \end{spacing} 9 | 10 | %\vspace*{14mm} 11 | \vfill 12 | 13 | \noindent \textgt{\bfseries\large 江添亮のC++17入門(仮)} 14 | 15 | \vspace{2mm} 16 | 17 | \noindent {\small 2018年x月x日 初版発行} 18 | \vspace{4mm} 19 | 20 | \noindent {\footnotesize 著 者}\hspace{3zw}\ruby{江添}{えぞえ} \ruby{亮}{りょう} \\ 21 | \noindent {\footnotesize 発行者}\hspace{3zw}川上量生 \\ 22 | \noindent {\footnotesize 発 行}\hspace{3zw}株式会社ドワンゴ 23 | \begin{spacing}{0.7} 24 | \noindent \hspace{5.5zw}{\footnotesize 〒 104-0061} \\ 25 | \noindent \hspace{5.5zw}{\footnotesize 東京都中央区銀座4-12-15歌舞伎座タワー} \\ 26 | \noindent \hspace{5.5zw}{\footnotesize 編集 03-3549-6153} \\ 27 | \noindent \hspace{5.5zw}{\footnotesize 電子メール \texttt{info@asciidwango.jp}} \\ 28 | \noindent \hspace{5.5zw}{\footnotesize \texttt{http://asciidwango.jp/}} \\ 29 | \end{spacing} 30 | \noindent {\footnotesize 発 売}\hspace{3zw}株式会社KADOKAWA 31 | \begin{spacing}{0.7} 32 | \noindent \hspace{5.5zw}{\footnotesize 〒 102-8177} \\ 33 | \noindent \hspace{5.5zw}{\footnotesize 東京都千代田区富士見2-13-3} \\ 34 | \noindent \hspace{5.5zw}{\footnotesize 営業 0570-002-301(カスタマーサポート・ナビダイヤル)}\\ 35 | \noindent \hspace{5.5zw}{\footnotesize 受付時間 9:00~17:00(土日 祝日 年末年始を除く)}\\ 36 | \noindent \hspace{5.5zw}{\footnotesize \texttt{http://www.kadokawa.co.jp/}} \\ 37 | \end{spacing} 38 | 39 | \noindent {\footnotesize 印刷・製本}\hspace{1.5zw}株式会社リーブルテック \\ 40 | \noindent {\footnotesize Printed in Japan} \\ 41 | 42 | \vspace{2mm} 43 | 44 | \begin{spacing}{0.8} 45 | %\noindent {\footnotesize 本書(ソフトウェア/プログラム含む)の無断複製(コピー、スキャン、デジタル化等)並びに\\ 46 | %無断複製物の譲渡および配信は、著作権法上での例外を除き禁じられています。また、本書を代\\ 47 | %行業者などの第三者に依頼して複製する行為は、たとえ個人や家庭内での利用であっても一切認\\ 48 | %められておりません。}\\ 49 | \noindent {\footnotesize 落丁・乱丁本はお取り替えいたします。下記KADOKAWA読者係までご連絡ください。}\\ 50 | \noindent {\footnotesize 送料小社負担にてお取り替えいたします。}\\ 51 | \noindent {\footnotesize 但し、古書店で本書を購入されている場合はお取り替えできません。}\\ 52 | \noindent {\footnotesize 電話 049-259-1100(9:00-17:00/土日、祝日、年末年始を除く)}\\ 53 | \noindent {\footnotesize 〒354-0041 埼玉県入間郡三芳町藤久保550-1}\\ 54 | \noindent {\footnotesize 定価はカバーに表示してあります。} 55 | \end{spacing} 56 | 57 | \vspace{2mm} 58 | 59 | \noindent {\footnotesize ISBN: 978-4-04-xxxxxx-x} \\ 60 | \begin{spacing}{0.7} 61 | \noindent {\footnotesize アスキードワンゴ編集部}\\ 62 | \noindent {\footnotesize 編 集  星野浩章} 63 | \end{spacing} 64 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | all : book 3 | 4 | clean : 5 | rm -f docs/index.html 6 | rm -f bin/sample-code-checker 7 | 8 | test : cpptest texttest 9 | 10 | texttest : *.md 11 | textlint -f unix *.md 12 | 13 | cpptest : test-tool 14 | bin/sample-code-checker *.md 15 | 16 | retest : test-tool 17 | bin/sample-code-checker retest /tmp/sample-code-checker/*.cpp 18 | 19 | test-tool : bin/sample-code-checker 20 | 21 | bin/sample-code-checker : bin/sample-code-checker.cpp 22 | g++ -D _ISOC11_SOURCE -std=c++14 --pedantic-errors -Wall -pthread -O2 -o bin/sample-code-checker bin/sample-code-checker.cpp 23 | 24 | book : docs/index.html 25 | 26 | 27 | docs/index.html : *.md style.css 28 | pandoc -s --toc --toc-depth=6 --mathjax -o $@ -H style.css pandoc_title_block *-*.md 29 | 30 | index.md : *.md 31 | pandoc -s --toc --toc-depth=6 --mathjax -o index.md -H style.css pandoc_title_block *-*.md 32 | 33 | .PHONY : all book clean test test-tool texttest cpptest retest 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C++17の新機能の差分本 2 | 3 | 著者:江添亮 4 | 5 | ブログ: https://cpplover.blogspot.jp/ 6 | 7 | とりあえず書く。 8 | 9 | [GitHub Pageで閲覧:C++17の新機能](https://ezoeryou.github.io/cpp17book/index.html) 10 | 11 | # 参考書の構成 12 | 13 | 参考書のソースコードはPandoc markdownで記述されている。 14 | 15 | ソースコードのファイル名は、"3文字の数字-記述内容の概要.md"となっている。ファイル名でソートした順番で結合される。 16 | 17 | C++のコード例のうち、すべての標準ヘッダーファイルが#includeされていればwell-formedなものは、 18 | 19 | ~~~~ 20 | ~~~cpp 21 | C++のコード例 22 | ~~~ 23 | ~~~~ 24 | 25 | で囲む。 26 | 27 | C++のコード例のうち、意図的にill-formedなものは、 28 | 29 | ~~~~ 30 | ~~~c++ 31 | C++のコード例 32 | ~~~ 33 | ~~~~ 34 | 35 | で囲む。 36 | 37 | 38 | # 参考書のビルド 39 | 40 | 参考書はmarkdownからpandocを使って目的のフォーマットに変換される。 41 | 42 | pandocを呼び出すためにMakefileを使っている。これはGNU Makeで使うことを前提として記述されている。 43 | 44 | 参考書をHTMLファイルにするには、makeを使う。index.htmlが生成される。 45 | 46 | ~~~ 47 | make 48 | ~~~ 49 | 50 | 参考書を単一のmarkdownファイルにするにはmakeを使う。index.mdが生成される。 51 | 52 | ~~~ 53 | make index.md 54 | ~~~ 55 | 56 | 57 | 58 | # 参考書を紙の本で印刷する工程 59 | 60 | 参考書を紙の本で印刷する場合、想定される工程は以下のようになる。 61 | 62 | ## アスキードワンゴから出版される場合 63 | 64 | 1. pandocを使ってmarkdownからtexに変換 65 | 1. 生成されたtexを編集者が手で編集 66 | 67 | ## その他の製本方法 68 | 69 | 以下は、大多数の出版社で想定される方法である。 70 | 71 | + pandocを使ってmarkdownからInDesign ICMLに変換。生成されたInDesignを手で編集。 72 | + markdownを編集者が目で読み、手でInDesignに入力。 73 | -------------------------------------------------------------------------------- /pandoc_title_block: -------------------------------------------------------------------------------- 1 | % 江添亮の詳説C++17 2 | % 江添 亮 3 | % 2017-02-28 4 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | 28 | --------------------------------------------------------------------------------