Skip to content

Latest commit

 

History

History
338 lines (257 loc) · 34.7 KB

cpp17.md

File metadata and controls

338 lines (257 loc) · 34.7 KB

C++17

概要

C++17とは、2017年12月に改訂され、ISO/IEC 14882:2017で標準規格化されたC++バージョンの通称である。

このバージョンは、策定中はC++1zと呼ばれていた。前バージョンであるC++11が策定中にC++0xと呼ばれ、C++14がC++1yと呼ばれており、「201z年にリリースされる」という年数の伏せ字として「z」が使われていた。

策定体制

C++14の策定開始段階から「Study Group (SG)」と呼ばれる専門家グループが複数作られ、そこで同時並行に新機能の議論、策定が進められていた。C++14ではそれらの機能は導入されなかったが、C++17ではSGで議論された機能のうち、仕様が固まったもののいくつかが導入されることとなった。

各SGで考えられた仕様は「Technical Specification (TS)」という単位で個別に各国の承認をとっている。その段階では、ライブラリ機能はstd::exprerimental名前空間などで各コンパイラが実験的にサポートをしていた。これはコンパイラが実装経験を積み、ユーザーが使用経験を得てから標準に採用するためである。

C++17では以下のTSが採用された:

TS 説明
Library Fundamentals TS 基本的なライブラリ機能。any, optional, string_view, メモリプール, 検索アルゴリズム, サンプリングアルゴリズム, タプルを展開して関数呼び出しするapply関数, shared_ptrの配列対応, 最大公約数と最小公倍数などが含まれる
Filesystem TS ファイルシステムのライブラリ
Parallelism TS 並列ライブラリ。<algorithm><numeric>に並列アルゴリズムが追加される

C++17以降、言語の策定にship train modelというリリース体制が設けられた。これは、3年ごとの定期的な言語アップデートを提供するために、「仕様が完成したらリリース」ではなく「完成した仕様から順次リリースに含める」という体制である。これにより、メジャーアップデート/マイナーアップデートというバージョンアップはなくなった。

言語機能

変数・データ構造関係

言語機能 説明
十六進浮動小数点数リテラル 十六進数表記で浮動小数点数リテラルを記述できるようにする
インライン変数 翻訳単位を跨いでひとつのオブジェクトになる変数を定義する
構造化束縛 組・タプル・配列を展開して変数定義する
波括弧初期化の型推論の新規則 波括弧初期化子が単一要素の場合は T に推論,複数要素の場合は不適格
[[maybe_unused]]属性 使用しない可能性のある変数に対する警告を抑制する
[[nodiscard]]属性 戻り値を捨ててはならないことを指定する
値のコピー省略を保証 右辺値を変数の初期化のために使用する場合、コピーもムーブも省略することを保証
厳密な式の評価順 式の評価順を規定する
参照メンバをもつクラスの置き換え 参照型メンバやconstデータメンバを含むクラスについてこれまで結果は未定義とされていた配置newによるオブジェクトの置き換えを条件付きで可能とする
enum class変数の初期値として整数を指定する際の規則を調整 キャストを使用することなく整数を初期値として使用し、E e{0};のような初期化を許可
アライメント指定されたデータの動的メモリ確保 operator newoperator deleteでアライメント値を取得できるようにする
集成体初期化の拡張 集成体初期化で基底クラスも入れ子に集成体初期化可能になる

制御構文

言語機能 説明
if文とswitch文の条件式と初期化を分離 if (init; condition)のように初期化と条件式を分けて記述できるようにする
[[fallthrough]]属性 フォールスルー時の警告を抑制する
constexpr if if constexpr(cond)とすることで、そのif文はコンパイル時に処理される
範囲 for ループの制限緩和 範囲 for 文の begin()end() が異なるイテレータ型を返せるようにすることで、終端イテレータを定義しやすくする

ラムダ式

言語機能 説明
ラムダ式での*thisのコピーキャプチャ キャプチャリストに*thisを指定することで、*thisをコピーキャプチャする
constexprラムダ ラムダ式の関数オブジェクトが定数式の文脈で使用された場合に、それがコンパイル時に評価されるようにする

テンプレート

言語機能 説明
畳み込み式 パラメータパックに対する二項演算の累積処理
テンプレートテンプレートパラメータにtypenameキーワードの使用を許可 classキーワードしか使用できなかった部分に、typenameを許可する
クラステンプレートのテンプレート引数推論 コンストラクタの引数からクラスのテンプレート引数を推論できるようにする
非型テンプレートパラメータのauto宣言 template <auto x>とすることで、X<3>; X<true>; X<'a'>のように定数を受け取りやすくする
全ての非型テンプレート引数の定数式評価を許可 ポインタの定数式評価として、配列からポインタへの変換や、関数から関数ポインタへの変換などを許可
using宣言のパック展開 パラメータパックの型を基底クラスとして指定した場合に、using宣言に基底クラスのパラメータパックを指定できるようにする
変数テンプレートのデフォルトテンプレート引数を許可 変数テンプレートのテンプレートパラメータがデフォルト引数を持つことを許可する

定数式

言語機能 説明
static_assertのメッセージ省略を許可 第2引数だった診断メッセージの省略を許可する
constexprラムダ ラムダ式の関数オブジェクトが定数式の文脈で使用された場合に、それがコンパイル時に評価されるようにする
if constexpr if constexpr(cond)とすることで、そのif文はコンパイル時に処理される

名前空間

言語機能 説明
入れ子名前空間の定義 namespace A::B {}のように、入れ子の名前空間を簡単に定義できるようにする
名前空間と列挙子への属性付加を許可 名前空間の定義と、列挙型の各要素の定義に、属性を付けられるようにする
using宣言のパック展開 パラメータパックの型を基底クラスとして指定した場合に、using宣言に基底クラスのパラメータパックを指定できるようにする

例外

言語機能 説明
例外仕様を型システムの一部にする 関数の型に例外仕様が含まれるようにする
非推奨だった古い例外仕様を削除 throwキーワードによる例外仕様を削除。throw()は残る

属性

言語機能 説明
[[fallthrough]]属性 フォールスルー時の警告を抑制する
[[maybe_unused]]属性 使用しない可能性のある変数に対する警告を抑制する
[[nodiscard]]属性 戻り値を捨ててはならないことを指定する
名前空間と列挙子への属性付加を許可 名前空間の定義と、列挙型の各要素の定義に、属性を付けられるようにする
属性の名前空間指定に繰り返しをなくす [[using CC: opt(1), debug]]のように属性の名前空間宣言をまとめて行う
不明な属性を無視する 実装が知らない名前空間の属性は無視する

プリプロセッサ

言語機能 説明
__has_include インクルードするファイルが存在するかを確認する

機能の削除

言語機能 説明
トライグラフの削除 現代では使用する必要がなくなったトライグラフ機能を削除
非推奨だったregisterキーワードを削除 コンパイラから単に無視されていたregisterキーワードを削除。予約語は残る
非推奨だったbool型に対するインクリメント演算子を削除 bool変数に対して++するとtrueになる仕様を削除
非推奨だった古い例外仕様を削除 throwキーワードによる例外仕様を削除。throw()は残る

小さな変更

ここでは、コア言語作業グループへ問題報告され、その解決策として導入された言語仕様の変更を解説する。

言語機能 説明
更新された定義済みマクロ 標準規格で定義されたマクロの更新
機能テストマクロ C++17 の機能がサポートされているかどうかをテストするためのマクロ
noexcept付きのラムダ式から変換する関数ポインタにnoexceptを付加する キャプチャを持たない非ジェネリックラムダにnoexceptを付加した場合、変換した関数ポインタにnoexceptを付加する
UTF-8文字リテラル UTF-8の指定が文字列リテラルに対してしかできなかったが、文字リテラルにもUTF-8指定をできるようにする

ライブラリ更新の概要

新ライブラリ

  • <filesystem>ヘッダを新設し、ファイルシステムライブラリを追加。ファイル、ディレクトリなどを扱う
  • <algorithm><numeric>のアルゴリズムに、並列実行のオプションを追加
  • <optional>ヘッダを新設し、統一的な有効値と無効値の表現をもつoptionalクラスを追加
  • <variant>ヘッダを新設し、型安全な共用体variantクラスを追加
  • <any>ヘッダを新設し、なんでも代入できるanyクラスを追加
  • 標準ライブラリの参照をC11に更新

コンテナ

  • コンテナのコピー・ムーブ、swap操作にnoexceptを追加
  • コンテナの要素情報にアクセスする非メンバ関数として、<iterator>size(), empty(), data()関数を追加
  • コンテナに不完全型の最小サポートを追加。vector, list, forward_listの要素型に、不完全型の指定を許可。ただし、これらのコンテナのなんらかのメンバ関数を呼び出す前には、要素型が完全型になっていること
  • 多相アロケータとメモリプール。<memory_resource>が新設され、アロケートする型を規定しないアロケータと、それを利用したメモリプールの仕組みが導入される
  • 標準イテレータ全般とarrayの変更操作にconstexprを追加
  • emplace_front()emplace_back()メンバ関数で、追加された要素を返すようにする
  • 連想コンテナの接合機能を追加。ほかのコンテナに要素を移すために抽出するextract()メンバ関数、抽出された要素をほかのコンテナに移すためのinsert()メンバ関数のオーバーロード、2つの連想コンテナをまるごと接合するmerge()メンバ関数を追加
  • mapunordered_mapに、挿入失敗時の動作を規定した新たなメンバ関数として、try_emplace()insert_or_assign()を追加
  • イテレータの分類に「隣接イテレータ (contiguous iterator)」を追加。要素間のメモリが隣接していることを表す。以下のコンテナのイテレータは、隣接イテレータであることが規定される:

アルゴリズム

文字列

並行処理

  • タイムアウト機能がないReaders-writer lockのミューテックスとして、shared_mutexクラスを追加
  • スコープ付きロックの可変引数版として、scoped_lockクラスを追加
  • atomicクラスに、指定された要素型に対するアトミック操作がロックフリー(非ミューテックス)に振る舞うかを判定するためにis_always_lock_free定数を追加
  • false sharingとtrue sharingを制御するための機能として、hardware_destructive_interference_size定数と、hardware_constructive_interference_size定数を追加

スマートポインタ

  • shared_ptrを配列に対応

  • shared_ptrクラスに、指定された要素型のweak_ptr型を表すweak_typeメンバ型を追加

  • shared_ptr::use_count()の仕様を明確化

  • shared_from_thisの指す先が書き換わらないことを規定

  • 配列版unique_ptrの型変換として、以下のコードが不適格だった:

    std::unique_ptr<Foo const * const []> ptr1(new Foo*[10]);
    Foo const * ptr = ptr1[9];
    • このようなコードが適格になるよう、変換コンストラクタと変換代入演算子を追加
  • unique_ptrのテンプレート代入演算子に、不足していたSFINAEルールを追加

  • owner_lessで、任意の要素型を持つshared_ptr同士を比較できるようにする

数学

タプル

  • タプルを展開して関数呼び出しするapply()関数を追加

  • タプルを任意の型のオブジェクトに変換するmake_from_tuple()関数を追加

  • 初期化子リストからpairtupleを構築しやすくするための改善として、以下のコードが適格になるようコンストラクタの仕様を調整:

    std::tuple<int, int> pixel_coordinates()
    {
      return {10, -15};  // コンパイルエラー
    }
    
    struct NonCopyable { NonCopyable(int); NonCopyable(const NonCopyable&) = delete; };
    
    std::pair<NonCopyable, double> pmd{42, 3.14}; // C++14ではコンパイルエラー
                                                  // C++17ではOK

型特性

時間演算

  • durationの丸め演算として、切り下げをするfloor()、切り上げをするceil()、最近接遇数への丸めをするround()、絶対値を求めるabs()を追加
  • time_pointの丸め演算として、切り下げをするfloor()、切り上げをするceil()、最近接遇数への丸めをするround()を追加
  • durationクラスとtime_pointクラスの変更操作をconstexprに対応

乱数

  • ランダムサンプリングアルゴリズムとして、sample()を追加
  • 乱数用語を変更。乱数生成器のコンセプトに 「URNG (Uniform Random Number Generator, 一様乱数生成器)」という用語を使用していたが、一般的なURNGの用語とは異なり、C++の乱数生成器は一度の呼び出しで、(32ビットを超えるような) より多くのビットを単一の符号なし整数にパックして返すという動作が許可されている。動作の誤解を避けるために、「URBG (Uniform Random Bit Generator)」という用語に変更する

エラーハンドリング

取り決め

  • std + 数字の名前空間を予約。C++の今後のバージョンアップで標準ライブラリに大きな変更を加えるときのために、「std + 数字」 (正規表現ではstd\d*) の名前空間が予約される

機能の削除

  • C++11から非推奨だった古いスマートポインタであるauto_ptrを削除。代わりにshared_ptrunique_ptrを使用すること
  • C++14から非推奨だった配列をランダムに入れ替えるrandom_shuffle()関数を削除。代わりにshuffle()を使用すること
  • C++11から非推奨だったthrowキーワードによる古い例外仕様に関連する、以下のライブラリ機能を削除する
  • C++11から非推奨だった古い<functional>の機能を削除
    • 引数を束縛するbind1st()関数、bind2nd()関数、binder1stクラス、binder2ndクラスを削除。代わりにbind()関数やラムダ式を使用すること
    • 関数ポインタから関数オブジェクトに変換するためのptr_fun()関数、pointer_to_unary_functionクラス、pointer_to_binary_functionクラスを削除。first_argument_typesecond_argument_typeといった型が必要なくなったため、これらの機能は必要なくなった
    • メンバ関数から関数オブジェクトへの変換をするためのmem_fun()関数、mem_fun_ref()関数、mem_fun_tクラス、mem_fun1_tクラス、mem_fun_ref_tクラス、mem_fun1_ref_tクラス、const_mem_fun_tクラス、const_mem_fun1_tクラス、const_mem_fun_ref_tクラス、const_mem_fun1_ref_tクラスを削除。代わりにmem_fn()bind()関数やラムダ式を使用すること
  • functionクラスのアロケータサポートを削除。コンパイラが実装していなかったり、不完全な実装だったりしていた
  • C++98から非推奨だったiostreamのエイリアスを削除
    • ios_base::io_stateの代わりにios_base::iostateを使用すること
    • ios_base::open_modeの代わりにios_base::openmodeを使用すること
    • ios_base::seek_dirの代わりにios_base::seekdirを使用すること
    • ios_base::streamoffの代わりに、char_traits<CharT>::off_typeもしくはbasic_ios<CharT>::off_typeを使用すること (<iosfwd>で定義されているstd::streamoffは残る)
    • ios_base::streamposの代わりに、char_traits<CharT>::pos_typeもしくはbasic_ios<CharT>::pos_typeを使用すること (<iosfwd>で定義されているstd::streamposは残る)
    • basic_streambuf::stossc()メンバ関数を削除。sbumpc()の単なる別名
    • ios_baseクラスの別名型が削除されることにともない、それらの型をパラメータにとるオーバーロードを削除
    • ios_baseクラスの別名型が削除されることにともない、それらの型をパラメータにとる関数が削除

機能の非推奨化

  • std::iteratorクラスを非推奨化。このクラスを使用しても、イテレータ定義は簡単にならなかった
  • C++11でallocator_traitsクラスが導入されたことで不要になった、allocatorの以下のメンバを非推奨化:
    • size_type
    • difference_type
    • pointer
    • const_pointer
    • reference
    • const_reference
    • rebind
    • address()メンバ関数
    • allocate()メンバ関数のhintパラメータ
    • max_size()メンバ関数
    • construct()メンバ関数
    • destroy()メンバ関数
  • C++11でallocator_traitsクラスが導入されたことで不要になった、要素型を再束縛するためのallocator<void>特殊化を非推奨化
  • constexprの機能拡張によって扱える型が増えている。将来的にほとんどの型がconstexprで扱えるようになるため、constexprで扱える型の分類であるis_literal_type型特性を非推奨化
  • 一時的なメモリ確保のためのstd::get_temporary_buffer()関数とstd::return_temporary_buffer()関数を非推奨化。これらは関数内での一時的なメモリ確保のために、最適化されたメモリ確保の仕組みを提供することを期待して定義されたが、実際にはどの実装も特別視せず、それゆえに便利に使われてはこなかった。将来的にスタックからのメモリ確保をする機能を作る予定だが、これらの関数は例外安全性やRAIIが考慮されていないため、これらの関数の実装・仕様のみを入れ替えるような改訂はできない
  • raw_storage_iteratorクラスを非推奨化。アロケータとの連携ができず、限られた用途にしか使用できなかった
  • not_fn()の追加にともない、古くなった以下の機能を非推奨化:
  • デバッグ用途にしか使用しない、shared_ptr::unique()を非推奨化
  • result_ofを非推奨化。代わりにinvoke_resultを使用すること
  • <codecvt>と関連する機能を非推奨化。適切なエラーハンドリングの方法がなかったため、セキュリティ上攻撃の可能性があった
  • memory_order_consumeを一時的に非推奨化。「その定義が現実に即していない」「acquire/releaseより弱いから使いにくい」といった理由から、より良い定義に変更するまでの間、非推奨とする
  • uncaught_exceptions()の追加にともない、古くなったuncaught_exception()を非推奨化

参照