What’s New In C++14 言語仕様¶
このノートでは C++14 で注目すべき言語仕様を学習する。すでに cpprefjp がそのへんをきれいに整理している。それを利用して、読みながら急所を記していくことにする。
タイピングの都合で訳語は cpprefjp のものと一部変更して記す。
言語機能¶
C++14 における言語機能の追加および変更は C++11 からのマイナーバージョンアップという程度に留まっている。
二進数リテラル¶
リテラル整数に prefix として 0b
または 0B
を付すと二進数として扱われる。
Python と同様。C/C++ にも存在して然るべき記法だ。
当然ながら数値部分は
0
または1
で尽くされる。
関数の戻り値に対する型推論¶
〈関数宣言の構文において、先頭の戻り値型を auto
もしくは decltype(auto)
とすることで、戻り値の型が関数の return
文から推論される〉機能が追加された。
コーディングが楽になる機能追加だ。
関数宣言構文はフリー関数だけでなく、非仮想メンバー関数に対しても使用できる。
先行宣言をする場合、その関数を使用するコードから関数の定義が見える必要がある。
複数の
return
文がある場合には、それらの式に共通する型が採用される。それらがバラバラである場合はコンパイルエラーだろう。戻り値の型を推論する関数宣言構文において、
{}
で囲まれた初期化子リストはreturn
文で返せない。
型推論 decltype(auto)
¶
decltype
に与える式を右辺の式で置き換えて型推論できるようになった。
cpprefjp の例を引用する。
int a = 3;
int b = 2;
decltype(auto) d = a + b;
この decltype(auto)
は decltype(a + b)
と置換されて、したがって int
だと推論される。
decltype(auto)
は、戻り値として変数への参照を返したい場合に使用する。
注意したいのは次のようなケース。上記の機能により f
の戻り値の型には auto
と書くことも考えられる。その場合は int
型関数として決定される。他方で
decltype(auto)
とすると関数 f
は int&
型となる。
decltype(auto) f(int& r)
{
return r;
}
後置戻り値型をプレースホルダーにしてよい¶
次の二種類の構文において ->
の次に auto
を書けるようになった。いつものように必要に応じて const
/volatile
, *
, &
, &&
を付けてもよい。
戻り値の型を後置する関数宣言構文
ラムダ式
ラムダ式の初期化捕獲¶
この機能はラムダ式の []
の部分に任意の式(の結果)を書けるというものだ。この角括弧で変数宣言と定義を同時にできると言っている。
汎用ラムダ¶
C++11 のラムダ式が拡張されて、パラメーターにテンプレートを使用できるようになった。ただしその構文はキーワード template
ではなく auto
を用いる:
auto plus = [](auto a, auto b) { return a + b; };
このラムダ式は意味としては次の関数テンプレートと同様だ:
template <class T1, class T2>
auto operator()(T1 a, T2 b) const
{
return a + b;
}
いつものように必要に応じて
const
/volatile
,*
,&
,&&
を付けてもよい。関数パラメーターパック
...
を併用してもよい。捕獲を含まない汎用ラムダはシグニチャーさえ一致すれば関数ポインターへ変換される。
変数テンプレート¶
関数テンプレート、クラステンプレートの類比で、変数(というか定数)もテンプレート化することができるようになった。 cpprefjp の例を引用する:
template <class T>
constexpr T pi = static_cast<T>(3.14159265358979323846);
これにより、円周率を参照する箇所で例えば pi<double>
のように書ける。
cpprefjp のサンプルコードが素晴らしい。一度はコンパイルして実行するといい。
キーワード constexpr
の制約が緩くなった¶
C++11 で導入されたこのキーワードは、C++14 で次のように適用範囲が広がる。型が
constexpr
である関数の定義において:
ふつうの変数宣言が許される。
if
文とswitch
文を書くことが許される。ループ文の存在が許される。
goto
は許されない。
変数の書き換えが許される。
ローカル変数を変更するコードが許される。
その関数が所属するクラスの非静的メンバー変数の書き換えが許される。
戻り値型として
void
が許される。要するに
constexpr void
型関数が書けるということだが、何の意味があるのかは知らない。
そして、constexpr
非静的メンバー関数に付く暗黙の const
修飾が C++14 で廃止される。これからは const
にも 非 const
にも書ける。
宣言時のメンバー初期化を持つ型に対して集成体初期化を許可¶
またしても cpprefjp の例を引用する。C++11 では次のように括弧を二度書くところを:
std::array<int, 3> ar = {{ 1, 2, 3 }};
C++14 では括弧を省略しても許される:
std::array<int, 3> ar = { 1, 2, 3 };
省略されているのは内側の括弧だそうだ。
属性 [[deprecated]]
¶
ライブラリー作者向けの機能だろう。提供している関数やクラスの一部が最新版で deprecated になったことを利用者に確実に知らせたい。そこで、対象となる関数やクラスにこの属性をマークすることで、コンパイラーがその旨を通知するということを期待される機能だ。
これは実際に利用するときになって仕様を確認するほうがいいだろう。
数値リテラルの桁区切り文字¶
Python などではアンダースコアを用いるところを C++ ではシングルクォーテーションを用いる。というか、アンダースコアを使いたくても既存機能(ユーザー定義リテラルでアンダースコアから始まる数値だけからなる suffix を定義できる)とバッティングするので使えなかったようだ。
サイズ付きメモリー領域割当解除¶
以下の演算子 operator delete
, operator delete[]
のオーバーロードが許される:
void operator delete(void* ptr, std::size_t size) noexcept;
void operator delete(void* ptr, std::size_t size,
const std::nothrow_t&) noexcept;
void operator delete[](void* ptr, std::size_t size) noexcept;
void operator delete[](void* ptr, std::size_t size,
const std::nothrow_t&) noexcept;
サイズ付き
operator new
,operator new[]
に対応するということはわかるだろう。クラス版ではなくフリー版というところがミソか。
定義済みマクロ¶
マクロ __cplusplus
の値が更新されて 201402L
となる。
機能テストマクロ¶
g++ (GCC) 10.0.2 ではすべて定義されていることを確認。使わないから覚えなくていい。
リテラル演算子宣言時の空白文字は省略してよい¶
下の行の記法でも許されるようになった。
return_type operator"" _xyz(const char*){ ... }
return_type operator""_xyz(const char*){ ... }
使わないから覚えなくていい。
型 nullptr_r
の定数式を非型テンプレートパラメータとしてよい¶
テンプレートリストの非型テンプレート引数として、つまり class
でも
typename
でもないようなテンプレート引数として、型 nullptr_t
を書くことが許される。
template <typename C, typename V, std::nullptr_t P>
class MyClass{
...
};