キーワード (C++)

本記事では、プログラミング言語C++におけるキーワードについて解説する。 本記事は、あくまでC++のキーワードに焦点をあてた記事であり、C++の全体像や、C++のキーワード以外の面には立ち入らない。読者の理解の助けとなる場合は適宜、他のプログラミング言語と比較する説明は行う。 なおC++のものに限らず、キーワード（keywords）、予約語（reserved words）、予約済みの識別子（reserved identifiers）といった概念全般や細かな違いについては「予約語」の記事を参照のこと。 最初に制定された規格であるISO/IEC 14882:1998（通称C++98）では63個のキーワードと11個の代替表現（alternative representations）が採用され、ISO/IEC 14882:2003（通称C++03）では追加のキーワードはなかった。ISO/IEC 14882:2011（通称C++11）で新たに13個のキーワードおよび2個の文脈依存キーワード（後述）が追加された。C++11から追加のキーワードおよび機能には(*)を付す。C++14およびC++17ではキーワードは増えていない。 C言語のC89/C90で存在したキーワードは、すべてがほぼそのままの形で取り入れられている。C95で追加されたwchar_tはキーワードではなかったが、C++ではキーワードとなった。中には、inlineなど最初C++98に導入されたキーワードが後からC99にも導入されたものもある。C11では同時期に策定されたC++11のalignas, alignof, static_assert, thread_localに直接対応するキーワードは追加されず、_Alignas, _Alignof, _Static_assert, _Thread_localというキーワードが追加され、C++互換の名前に関しては別途マクロとして提供するヘッダーが追加された。C23では改めてC++同様のキーワードが追加され、C11で追加された古いキーワードの多くは非推奨となる予定である。 ヌルポインタ (null pointer) を表す。この値はあるstd::nullptr_t型のオブジェクトで、任意のポインタ型のヌルポインタ値に暗黙変換できるが、整数型には暗黙変換できない。なお、従来のNULLマクロは、もともとC++98の時点で実装定義のヌルポインタ定数 (null pointer constant) に展開される仕様だったが、C++ではヌルポインタ定数の1つとして整数リテラル0を任意のポインタに代入することができるため、C++03までは整数リテラル0に展開される実装が一般的だった。C++11以降はnullptrに展開される実装もありえることになる。 複数のキーワードを組み合わせることで意味が変わるものが多い（文脈依存のキーワード）。 short単体では符号付き短整数型signed short intを、long単体では符号付き長整数型signed long intを意味する。long long intは少なくとも64ビットの精度を持つ整数型である(*)。 long doubleは少なくともdoubleと同じ精度を持つ浮動小数点数型。処理系によっては拡張倍精度浮動小数点数型となる。 C99ではマクロで定義されておりキーワードではないが、C++ではキーワードである。 wchar_tは、Cではtypedefによる型エイリアスでありキーワードでないが、C++ではキーワードである。 char16_tとchar32_tは、それぞれUTF-16およびUTF-32の文字を格納するための整数型を表す。 戻り値や引数がないことを表す型。 デリファレンスする先の型を指定しないポインタvoid*の表現に用いられる。 変数宣言の際に型として指定すると、初期化式から型推論を行う。 また、戻り値型を後置きする関数宣言に用いる。 // 以下の2つは同じ宣言。 int main(int argc, char** argv); auto main(int argc, char** argv) -> int; C++においてstructはデフォルトのアクセス制御がpublicであること以外はclassと全く同じである。unionもクラスの一種という扱いである。 unionはすべてのメンバ変数が同一メモリ領域を共有するのはCのままであるが、classに準じてメンバ関数を持てるようになっている。 なお、C++規格では、クラス内で宣言した変数および関数は、それぞれデータメンバ（data member）およびメンバ関数（member function）と呼ぶ。データメンバはメンバ変数と呼ばれることも多い。JavaやC#のように、フィールド・メソッドなどといった用語は使われない。 enum単独ではスコープのない列挙型を意味する。enum class、enum structの形で、スコープ付きの列挙型の宣言に使用する(*)。 Cの書き換え不能という意味に加え、定数の意味が加わっている。具体的にはCと違いブロックスコープにない場合、定数扱いとなり、externを指定しない限り内部結合になる。プリプロセッサによるマクロの代替的手段になる。 const int N = 16; int Array[N]; このコード片で、CではNが定数ではないのでArrayの宣言はエラーになる。C99でもグローバル変数は可変長配列にできないのでやはりエラーになる。 クラス内では、整数型をstatic constで修飾するとクラススコープの定数の定義になる。詳しくはstaticを参照のこと。 volatileの指定された記憶領域は、実行しているコードが書き換えを行わない場合にも、何らかの理由で内容が書き換えられる可能性を持つ。書き換えの起きる具体的な要因としては、何らかのハードウェアによる書き換えが挙げられる。 コンパイラによる最適化では、メモリを書き換えない限り内容が変わらないことを利用し、メモリからの再読み込みの省略などを行うが、例えばあるメモリ領域にハードウェアが書き込んでいて、そのメモリ領域の変化を読み取りループで監視しようとするならば、volatile指定が無い場合はコンパイラが「書き込みを行っていないのでメモリ内容が変化する可能性は無い」と判断し、ループを消し去ったり、メモリを再読み込みせずに単純な無限ループを行ったりするなど、期待と異なる最適化を行う可能性が高い。そのような場合、volatileを適切に指定することで、メモリ領域を正しくポーリングすることが期待できる。 また、コンパイラによっては、volatileの指定された記憶領域へのアクセス前後において、適切なメモリバリアを自動的に配置することもある。が、逆にメモリバリアについては一切関知しないものもあるため、ノンブロッキング同期プログラミングなどでは特別な注意が必要となる。 ハードウェアに近い操作を行う処理を記述する際は、特に重要になる修飾子である。 C++03以前では自動変数 (automatic variable) を意味する記憶クラス指定子 (storage class specifier) であったが、C++11で廃止され、型推論のための全く別の機能が割り当てられた。 もともと、関数のようなブロックスコープ内の変数（ローカル変数）に記憶クラスを指定しなかった場合はデフォルトで自動記憶域期間 (automatic storage duration) を持つ自動変数となるため、C++03以前においても記憶クラス指定子としてのautoを用いる必要は全くなかった。前方互換性のためにも、むやみに使用すべきではない。なお、C++11以降も自動記憶域期間を持つ変数を表す用語は「自動変数」のままであり変更はない。 Cからの外部結合の指定に加え、リンケージ指定の用法が加わっている。 C++では名前（関数名や変数名など）に対して多重定義や名前空間、型安全の保証などの都合から、多くのコンパイラは名前修飾を施しCとは異なった名前をリンカに対して用いている。その名前の修飾の仕方を指定するのがリンケージ指定である。少なくとも"C"と"C++"の2種類のリンケージが使用できる。何も指定しないと"C++"になる。"C"リンケージでは名前の変形を抑止しCと互換の名前をリンカに対して用いることを意味する。これによりCとC++を混在させてプログラムを作るときに使われる。 //a.cpp extern "C" { int a; //Cリンケージの変数定義 extern int b; //Cリンケージの変数宣言 void f(); //Cリンケージの関数宣言 } extern "C" int c; //リンケージ指定と元々の外部結合の意味を兼ねた用法。 //b.c extern int a; //変数の宣言 int b; //変数の定義 int c; void f() { /* ... */ } また、extern templateの形でテンプレート実体化宣言を修飾して、外部で実体化されたテンプレートを指定する(*)。 C++17以降では何の機能もないキーワードである。将来のために予約されている。 C++14以前では、特にレジスタに割り当ててほしい自動変数に指定する記憶クラス指定子であった。Cよりも意味合いが弱く、Cのregister変数はアドレス参照（&演算子によるポインタ取得）を行えないが、C++では行えた。つまり、register変数として宣言してもメモリに配置されうる。コンパイラが高度な最適化を行う場合、レジスタに配置すべき変数の判断はコンパイラの方が適切に行えることが多いので、C++14以前のコンパイラでも、この指定を無視するのが一般的であった。 ファイルスコープの指定（Cからの用法）。ただし、ファイルスコープを指定するのにstaticを用いるのはC++では推奨されず、無名名前空間を用いるべきとされている。 クラス・関数の静的変数とクラスの静的関数（関数内静的変数についてはCからの用法）。 特にクラスの場合、これは宣言となるため普通のグローバル変数などと同様にソースファイルで定義が必要である。ただし次の場合、例外として不要である。 整数型にconstと共に指定し宣言と同時に初期化した場合。クラススコープの定数となる。 クラスの静的メンバ関数の場合。（クラス宣言とは別にソースファイルで定義をしてもよいし、クラス内にインラインで定義してもよい） // ヘッダbar.h class bar { static int a; // OK: 静的メンバ a の宣言。 static const int b = 5; // OK: 静的メンバ b の宣言と定義。クラススコープの定数となる。 static const double c; // OK: 静的メンバ c の宣言。 // static const double d = 2.0; // Bad: 整数型でない。 static void f(); // OK: 静的メンバ f の宣言。 static void g() { /* ... */ } // OK: 静的メンバ g の宣言と定義。 }; // ソースbar.cpp #include "bar.h" int bar::a = 1; // OK: bar::a の定義。 //const int bar::b = 5; // クラススコープの定数は定義する必要がない。 const double bar::c = 3.0; // OK: bar::c の定義。 void bar::f() // OK: bar::f の定義。 { /* ... */ } 古いC++処理系では整数型をstatic constで修飾することによる定数の定義ができなかったので、代わりにクラス内に定義した列挙型 (enum) による列挙定数で代用をすることがしばしばあった。これはenumハックと呼ばれる。 C++11以降はconstexprを併用することで、クラス宣言部で定数定義できる型が増加した。 constなオブジェクトでも書き換え可能にしたいクラスメンバ変数に指定する。 ラムダ式を修飾して、コピーキャプチャした変数の書き換えを許可する(*)。 グローバル変数やクラス・関数内静的変数について、スレッドローカルな記憶域に確保するよう指示する。 フレンド関数・フレンドクラスの宣言に用いる。 定数式を表す。変数や関数を修飾して、コンパイル時定数となりうることを指示する。 コンストラクタに指定して暗黙の型変換に用いないことを指定する。 変換関数を修飾して、暗黙の型変換に用いないことを指定する(*)。 関数指示子に使用することで、関数をインライン展開するためのヒントをコンパイラに与える。クラスの宣言内で関数を定義した場合は、inlineの有無にかかわらずinlineが指定されたものとして取り扱われる。 inline namespaceの形で透過的な名前空間の宣言に用いる。透過的な名前空間の名前は、名前空間名で修飾しなくても使えるようになる(*)。 仮想関数を宣言する。C++ではこれを明示しないと派生クラスでポリモーフィックにオーバーライドすることはできない。派生クラスではオーバーライドするときに特に何か指定する必要はないが、virtualを省略しないスタイルも一般的である。 仮想継承するときにベースクラスの指定に修飾する。 クラスメンバと継承のアクセス制御に用いられる。 publicはクラスの外部からも自由にアクセスできる。 protectedは宣言したクラス自身とその派生クラスからアクセスできる。 privateは宣言したクラスの内部からしかアクセスできない。 Javaなどとは違い個々の宣言に付けるものではなく、見た目には関数内でラベルを指定するのと似ている。1度指定すると他の指定がなされるか、クラスの宣言が終わるまでは指定した制御が続く。 class foo { int n; //classであり、まだアクセス制御が指定されていないのでprivateになる public: foo(int); //コンストラクタ ~foo(); //デストラクタ int getN(); //メンバ関数 //ここまでの3つはすべてpublicになる protected: void setN(int); //protectedになる }; //クラス宣言の終わりには ; が必要。 class hoge : private foo //private継承 外部からはhogeのインスタンスを通じてfooのメンバにはアクセスできない。 { public: using foo::getN; //このように個別にアクセス制御を上書きすることもできる。 hoge(); ~hoge(); }; 演算子多重定義（オペレータオーバーロード）の関数を定義するのに用いる。 自分のクラスから他の型へ、暗黙の型変換を行う関数を定義するのに用いる。なお、他の型から自分のクラスへの変換は1引数のコンストラクタを使用する。 ユーザー定義リテラルの定義に用いる。operator"" suffixは接尾辞suffixで記述するユーザー定義リテラルを定義する関数名である(*)。 自分自身へのポインタ。当然ながらクラスの非静的メンバ関数内でのみ使用できる。参照でなくポインタである理由は、thisがC++に導入された当時まだ参照がなかったからである。 defaultは関数の定義にも用いる。特殊メンバ関数を「= default」の形で定義して、コンパイラ生成のものを使用することを明示する(*)。 newはヒープにオブジェクトまたは配列を割り当てるnew演算子とnew[]演算子に用いられ、deleteはそれを解放するdelete演算子とdelete[]演算子に用いられる（[]の有無で演算子は区別される）。JavaやC#などと違い、C++はガベージコレクションを持たないので、オブジェクトが不要になったら明示的に破棄する必要がある。もっとも、C++ではオブジェクトの構築に動的メモリ確保（動的記憶域期間）は必須ではなく、自動記憶域期間または静的記憶域期間を持つオブジェクトを定義してもよく、またスマートポインタやSTLコンテナのようなRAIIクラスを用いてnew/new[]とdelete/delete[]の手間を省くようにすることはできるため、アプリケーションソフトウェアのような実践的なプログラムではnew/new[]やdelete/delete[]が直接的に使用されることは少ない。 deleteは関数の定義にも使用される。関数を「= delete」の形で定義して、そのシグネチャの関数を存在させないことを指示する(*)。 型変換（キャスト）は注意を要する操作であるにもかかわらず、Cの型変換演算子はあまりにも目立たず、目的がコードから見えにくいという理由からC++では、型変換を行う場合には用途ごとの4つの型変換演算子を用いることが推奨されている。 動的キャスト。RTTIを用いて、目的の型に変換できるかどうかを確認し、不可能であればポインタの場合ヌルポインタを返し、参照の場合はstd::bad_cast例外を投げる。また、Cにない概念のため、Cの型変換演算子で代用できない。 静的キャスト。コンパイル時に型チェックを行う。変換前の型から変換後の型へ、あるいはその逆向きの暗黙の変換が存在する場合に変換可能である。変換できなければコンパイルエラーになる。 const/volatile性を取り除く場合に用いるキャストである。他のキャストでconst/volatile性が失われる変換はできない。 安全でなかったり移植性のない型変換に用いる。無関係なポインタ型同士の変換や、ポインタと整数型の変換などがそうである。 型のアライメントの値を得る。 式から型を取得し、型名として用いる。 型、あるいは式の型のサイズを得る。 また、sizeof...の形で、可変長引数テンプレートの可変長引数部の長さを取得する(*)。 例外を投げる。また、後述の例外指定の用法もある（C++11以降でこの用法は非推奨）。 関数に例外指定を付与する。 //noexceptはどんな例外も投げないことを示す。 int func2() noexcept; //noexceptはコンパイル時定数となる引数を取ることができ、trueならnoexceptと同じ。 int func3() noexcept(true); //falseならあらゆる例外を投げる可能性がある。 int func4() noexcept(false); //noexceptと等価な記述。 int func5() throw(); //noexcept(false)と等価な記述。 int func6() throw(...); //この関数から投げられる例外はstd::exception型（とその派生クラス型）かint型しかありえないことを示す。この用法は非推奨。 int func7() throw(std::exception, int) {/* ... */} C++11以降は、throwを用いた例外指定は推奨されない。C++03以前でも、throwを用いた例外指定は例外安全のうち例外を投げない表明としてfunc5のように型を無指定にして用いられる場合が大半であった。 また、noexceptは例外指定の有無を判定する式としても用いられる。 //b2はtrue bool b2 = noexcept(func2()+1); //b4はfalse bool b4 = noexcept(func4()+func7()); コンパイル時に評価される表明を記述する。検査式が偽になると、指定されたメッセージを伴ってコンパイルエラーとなる。宣言として扱われるが、プログラムの動作には影響がない。 static_assert(sizeof(Foo) == 4, "Unexpected: the size of Foo must be 4"); クラステンプレート・関数テンプレートの宣言あるいは定義。特殊化や部分特殊化にも使う。 クラステンプレート・関数テンプレートの明示的実体化。 メンバテンプレートをテンプレート引数を明示して使用する場合にはこれを先行しなければならない。理由はテンプレート引数の < > と不等号演算子との区別をつけるためである。 テンプレート引数で型を引数にとることを示すことに使う（classで代用可能）。 続く識別子が型名であることを示す。 //typenameの例 template <typename T> struct s1 //1の用法 { void f() { typename T::type *ptr; //2の用法 } }; 用法2.はなぜ存在するのかというと、曖昧性が生じさせないためである。 たとえばs1に次のようなクラスをテンプレート引数に渡すとする。 struct s2 { static const int type = 0; }; すると、仮にtypenameがなければs1<s2>::fの中の文はs2::type *ptr;となる。これはs2::typeとptrの乗算式と見られるので、構文としては正当なC++の式となってしまう（ただしこの例ではptrが宣言されていないためコンパイルエラーになる）。そうならないように、曖昧性を排除するために型名である場合はtypenameを先行させる仕様になっている。 C++11では何の機能もないキーワードである。将来のために予約されている(*)。 C++03以前では、分離コンパイルを行うクラス・関数テンプレートに指定するものであった。分離コンパイルとは、通常の関数などのようにヘッダに宣言を書いて、どこかのソースファイルに定義を書く形式のことである。これを指定しないとテンプレートは通常ヘッダに定義を書く必要がある。 このキーワードに対応しているコンパイラは、一般に広く知られたものではComeau C++のみである。対応しない多くのコンパイラでは、このキーワードは単に無視されるか、キーワードとして扱われない場合さえある。 名前空間の宣言 (namespace NS { /* ... */ }) 名前空間は入れ子にすることができる。 名前空間名を省略すると無名名前空間の宣言になる。無名名前空間の中にある宣言は他の翻訳単位から見えない。 usingディレクティブ（usingを参照） 名前空間のエイリアス (namespace NS2 = NS;) using宣言 (using NS::NAME;) usingディレクティブ (using namespace NS;) アクセス宣言 - public, protected, privateのclass Hogeの例を参照。 テンプレートの別名を定義する(*)。 asm(文字列リテラル)という構文が定まっているだけで、その文字列リテラルの書式等は処理系依存である。多くのコンパイラではインラインアセンブラを利用するために用いる。 変数宣言を修飾するアトリビュートで、変数のアライメントを指定する。 文脈依存のキーワード(contextual keyword)は、ソースコード中の特定の位置に現れた場合にのみキーワードとして扱われ、それ以外の箇所では単なる識別子として扱われる（変数名や関数名として使用出来る）。C++11から新たに追加された。 メンバ関数の宣言の直後、またはクラス宣言のクラス名の直後において文脈依存のキーワードとして扱われる。メンバ関数の宣言の直後では、その関数がオーバーライドされることを禁止する｡クラス名の直後では、そのクラスから派生すること（基底クラスとして用いられること）を禁止する。 メンバ関数の宣言の直後において文脈依存のキーワードとして扱われる。仮想関数が基底クラスのメンバ関数をオーバーライドすることを明示する。 代替字句(alternative token)のうちの、記号ではなくアルファベット（と下線）で表現する代替表現（alternative representation）は、キーワードには列挙されていないが、キーワードと同様に扱われる。ISO 14882の英語版の注ではlexical keywords（字句的にはキーワードであるもの）という表現が使われているが、JIS X 3014:2003の注では「予約語」という用語を用いて説明されている。 C/C++ではASCIIの記号類を多用しているので、ISO/IEC 646のUS以外を使用している環境では問題がある。それらの代用として、問題のない文字だけで表現するのが代替字句である（同じ用途のものとして他にトライグラフがある）。代替字句のうち、記号で表すダイグラフ（規格票の用語では「二つ組」）以外が代替表現である。これらはCではマクロ（ヘッダiso646.h、C95で標準化された）だが、C++では言語の一部である。 以下にそれぞれ対応する演算子を示してある。 and && and_eq &= bitand & bitor | compl ~ not ! not_eq != or || or_eq |= xor ^ xor_eq ^= C99 のキーワードのうち _Bool, _Complex, _Imaginary, restrict は C++ のキーワードではない。C11 で追加になったキーワードのうち _Alignas, _Atomic, _Generic, _Noreturn, _Static_assert, _Thread_local は C++ のキーワードではない。C99 の _Bool には C++ の bool が対応する。また、_Complex に関しては、代わりに std::complex クラステンプレートが標準C++ライブラリに存在する。 C++の次期規格C++20では、機能の追加に伴い、新しいキーワードの追加、既存のキーワードへの意味の追加が予定されている。 char8_t （基本型）UTF-8の文字を格納するための整数型を表す。 concept （新機能：コンセプト）コンセプトを定義する。コンセプトは、型が満たすべき要件に名前を与える新しいプリミティブである。 consteval （関数指定子）変数や関数を修飾して、コンパイル時定数となることを指示する。constexprと異なり、コンパイル時に評価することを強制する。 requires （新機能：コンセプト）テンプレート引数のコンセプト要求を指定する定数式を指定する。 audit, axiom （アトリビュート）expects, ensures, assertのいずれかのアトリビュートの内部で、アトリビュート名の直後に出現した際に文脈依存のキーワードとして扱われる。これらのアトリビュートはそれぞれ関数についての事前条件、事後条件、不変条件の契約を示すための新しいアトリビュートである（契約プログラミング）。各アトリビュートの契約にはdefault, audit, axiomの三段階の契約レベルがあり、これらの文脈依存のキーワードはaudit契約レベルおよびaxiom契約レベルの指定に利用する（default契約レベルはキーワードdefaultか、または指定を省略することによって指定する）。おおむね、defaultは実行時チェックの負荷が小さいもの、auditは実行時チェックの負荷が大きいもの、axiomは実行時チェックを意図しないものに指定することを規格では意図している。実際にどの契約レベルまで実行時にチェックするかは、「ビルドレベル」によって変更される。 ^ Cの標準規格では、_とそれに続く大文字アルファベットで始まる名前は処理系によって予約される規則となっており、既存の処理系のライブラリ実装に使われているコードと名前衝突が発生する可能性はあるものの、規格に準拠したアプリケーションコードであれば名前衝突は発生せず、既存のユーザーコードの互換性を破壊しないことが保証される。Cでは新たなキーワードの追加にあたって、影響の大きさを鑑み、C++よりも慎重な配慮がなされることになった。 ^ C99のboolはtypedefではなくマクロで定義されることが規格で規定されている。 ^ 「メンバ」は長音符号を付けて「メンバー」と表記されることも多いが、ここではISO/IEC 14882:2003の日本語訳である「JIS X 3014:2003 プログラム言語C++」における表記に従った。 ^ 識別子 - cppreference.com ^ C keywords - cppreference.com ^ ISO/IEC 14882:1998, C.2.2.3 Macro NULL ^ NULL - cppreference.com ^ Storage class specifiers - cppreference.com ^ 静的メンバ - cppreference.com ^ Stroustrup, Bjarne (1994). The Design and Evolution of C++. Addison-Wesley. pp. 2.5.2. ISBN 0-201-54330-3  （日本語訳： 『C++の設計と進化』ソフトバンクパブリッシング、2005年。ISBN 4-7973-2854-1。  ） ^ [1] ISO/IEC 14882:2003 “Programming languages -- C++” JIS X 3014:2003 『プログラム言語C++』 ISO/IEC 14882: Programming Language C++ Working Paper (N2798) 予約語 C++ キーワード (C言語) CとC++の演算子