概要
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年ごとの定期的な言語アップデートを提供するために、「仕様が完成したらリリース」ではなく「完成した仕様から順次リリースに含める」という体制である。これにより、メジャーアップデート/マイナーアップデートというバージョンアップはなくなった。
言語機能
変数・データ構造関係
言語機能 | 説明 |
---|---|
16進浮動小数点数リテラル | 十六進数表記で浮動小数点数リテラルを記述できるようにする |
インライン変数 | inline 指定をすることで翻訳単位を跨いでひとつのオブジェクトになる変数を定義する |
構造化束縛 | 組・タプル・配列を展開して変数定義する |
単一要素の波カッコ初期化を非配列とする | 波カッコ初期化子が単一要素の場合は T に推論,複数要素の場合は不適格 |
[[maybe_unused]] 属性 |
使用しない可能性のある変数に対する警告を抑制する |
[[nodiscard]] 属性 |
戻り値を捨ててはならないことを指定する |
値のコピー省略を保証 | 右辺値を変数の初期化のために使用する場合、コピーもムーブも省略することを保証 |
厳密な式の評価順 | 式の評価順を規定する |
参照メンバをもつクラスの置き換え | 参照型メンバやconst メンバ変数を含むクラスについてこれまで未定義動作とされていた配置new によるオブジェクトの置き換えを条件付きで可能とする |
enum class 変数の初期値として整数を指定する際の規則を調整 |
キャストを使用することなく整数を初期値として使用し、E e{0}; のような初期化を許可 |
アライメント指定されたデータの動的メモリ確保 | operator new とoperator delete でアライメント値を取得できるようにする |
基底クラスのメンバ変数を集成体初期化するための波カッコを省略できるようにする | 基底クラスのメンバを集成体初期化するために、 derived d {{42}}; の代わりに derived d {42}; と書けるようにする |
制御構文
言語機能 | 説明 |
---|---|
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に更新
<cfloat>
に、非正規化数の有無を判定するマクロ、10進数の桁数を表すマクロ、正の最小数を表すマクロを追加<cstdlib>
に、aligned_alloc()
関数を追加<ctime>
に、TIME_UTC
マクロ,timespec
構造体,timespec_get()
関数を追加<cstdio>
に、vfscanf()
関数を追加<ccomplex>
,<cstdalign>
,<cstdbool>
,<ctgmath>
を非推奨化
コンテナ
- コンテナのコピー・ムーブ、
swap
操作にnoexcept
を追加 - コンテナの要素情報にアクセスする非メンバ関数として、
<iterator>
にsize()
,empty()
,data()
関数を追加 - コンテナに不完全型の最小サポートを追加。
vector
,list
,forward_list
の要素型に、不完全型の指定を許可。ただし、これらのコンテナのなんらかのメンバ関数を呼び出す前には、要素型が完全型になっていること - 多相アロケータとメモリプール。
<memory_resource>
が新設され、アロケートする型を規定しないアロケータと、それを利用したメモリプールの仕組みが導入される - 標準イテレータ全般と
array
の変更操作にconstexpr
を追加 emplace_front()
とemplace_back()
メンバ関数で、追加された要素を返すようにする- 連想コンテナの接合機能を追加。ほかのコンテナに要素を移すために抽出する
extract()
メンバ関数、抽出された要素をほかのコンテナに移すためのinsert()
メンバ関数のオーバーロード、2つの連想コンテナをまるごと接合するmerge()
メンバ関数を追加 map
とunordered_map
に、挿入失敗時の動作を規定した新たなメンバ関数として、try_emplace()
とinsert_or_assign()
を追加- イテレータの分類に「隣接イテレータ (contiguous iterator)」を追加。要素間のメモリが隣接していることを表す。以下のコンテナのイテレータは、隣接イテレータであることが規定される:
basic_string
array
bool
以外を要素型とするvector
valarray
(の非メンバ関数であるstd::begin()
、std::end()
で返されるイテレータは隣接イテレータ)
アルゴリズム
- ランダムサンプリングアルゴリズムとして、
sample()
を追加 - 並列アルゴリズムの追加にともない、
<algorithm>
にfor_each_n()
を追加 - 並列アルゴリズムの追加にともない、
<numeric>
に以下を追加:accumulate()
の計算順序を規定しないバージョンである、reduce()
を追加- 部分和を求める関数
partial_sum()
を、i番目の部分和を求める際にi番目の要素を含める・含めないで分割し、inclusive_scan()
とexclusive_scan()
を追加 - 値を変換しながら畳み込む
transform_reduce()
を追加 - 値を変換しながら部分和を求める関数として、
transform_inclusive_scan()
とtransform_exclusive_scan()
を追加
- 値を範囲内に収める
clamp()
関数を追加 bool
を返す関数オブジェクトの結果を反転させるnot_fn()
関数を追加- INVOKE要件に従った関数呼び出しをする
invoke()
関数を追加 reference_wrapper
がTriviallyCopyableであることを保証- オブジェクトを
const
にするas_const()
関数を追加 - 未初期化メモリのアルゴリズムと、デストラクタ呼び出しの関数として、以下の関数を追加:
destroy_at()
,destroy()
,destroy_n()
,uninitialized_move()
,uninitialized_move_n()
,uninitialized_value_construct()
,uninitialized_value_construct_n()
,uninitialized_default_construct()
,uninitialized_default_construct_n()
文字列
<string_view>
ヘッダを新設し、所有権を持たない文字列クラスであるbasic_string_view
を追加basic_string::data()
メンバ関数の非const
版を追加- 文字列検索アルゴリズムとして、「ボイヤー・ムーア法 (Boyer-Moore)」の
std::boyer_moore_searcher
関数オブジェクトと「ボイヤー・ムーア・ホースプール法 (Boyer-Moore-Horspool)」のstd::boyer_moore_horspool_searcher
関数オブジェクトを追加。std::search()
関数のポリシーとして、検索アルゴリズムを指定する - ロケール依存なし、フォーマット解析なしの高速な文字列・数値変換関数として、
to_chars()
とfrom_chars()
を追加 char_traits
クラスをconstexpr
に対応- バイトデータを表す
byte
型を追加
並行処理
- タイムアウト機能がない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()
関数を追加 -
初期化子リストから
pair
とtuple
を構築しやすくするための改善として、以下のコードが適格になるようコンストラクタの仕様を調整: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
型特性
- 値を返す型特性クラスの
constexpr
変数テンプレート版を追加。変数テンプレート版は、末尾に_v
が付く。v
はvalue
(値) を意味する - 型特性クラスを定義しやすくするために、
void_t
を追加 bool
定数を表すbool_constant
を追加- コンパイル時条件の論理演算のために、論理積である
conjunction
、論理和であるdisjunction
、否定であるnegation
を追加 swap
可能かを判定する型特性クラスとして、is_swappable_with
、is_swappable
、is_nothrow_swappable_with
、is_nothrow_swappable
を追加- 関数が呼び出し可能かを判定する型特性として、
is_invocable
、is_invocable_r
、is_nothrow_invocable
、is_nothrow_invocable_r
を追加 - 自動的にハッシュ値が求められる型かを判定するために
has_unique_object_representations
型特性を追加 invoke()
の追加にともない、関数の戻り値型を取得する型特性invoke_result
を追加。これまでのresult_of
と違って関数型のテンプレート引数を使用しないため、それによって起こっていた厄介な問題を回避する
時間演算
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)」という用語に変更する
エラーハンドリング
- 現在発生している例外の数を取得する
uncaught_exceptions()
関数を追加
取り決め
std
+ 数字の名前空間を予約。C++の今後のバージョンアップで標準ライブラリに大きな変更を加えるときのために、「std
+ 数字」 (正規表現ではstd\d*
) の名前空間が予約される
機能の削除
- C++11から非推奨だった古いスマートポインタである
auto_ptr
を削除。代わりにshared_ptr
かunique_ptr
を使用すること - C++14から非推奨だった配列をランダムに入れ替える
random_shuffle()
関数を削除。代わりにshuffle()
を使用すること - C++11から非推奨だった
throw
キーワードによる古い例外仕様に関連する、以下のライブラリ機能を削除するunexpected()
set_unexpected()
get_unexpected()
unexpected_handler
noexcept
による例外仕様では、例外を送出しないはずの関数から例外が送出された場合、terminate()
関数によって即座にプログラムが異常終了するため、想定されていない例外が送出された場合のハンドリングは機能しない
- C++11から非推奨だった古い
<functional>
の機能を削除- 引数を束縛する
bind1st()
関数、bind2nd()
関数、binder1st
クラス、binder2nd
クラスを削除。代わりにbind()
関数やラムダ式を使用すること - 関数ポインタから関数オブジェクトに変換するための
ptr_fun()
関数、pointer_to_unary_function
クラス、pointer_to_binary_function
クラスを削除。first_argument_type
やsecond_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()
の追加にともない、古くなった以下の機能を非推奨化:not1()
関数not2()
関数unary_negate
クラスbinary_nagate
クラス- 標準関数オブジェクトの
result_type
、argument_type
、first_argument_type
、second_argument_type
型
- デバッグ用途にしか使用しない、
shared_ptr::unique()
を非推奨化 result_of
を非推奨化。代わりにinvoke_result
を使用すること<codecvt>
と関連する機能を非推奨化。適切なエラーハンドリングの方法がなかったため、セキュリティ上攻撃の可能性があったmemory_order_consume
を一時的に非推奨化。「その定義が現実に即していない」「acquire/releaseより弱いから使いにくい」といった理由から、より良い定義に変更するまでの間、非推奨とするuncaught_exceptions()
の追加にともない、古くなったuncaught_exception()
を非推奨化