「キーワード (C++)」の版間の差分
編集の要約なし |
|||
42行目: | 42行目: | ||
また、戻り値型を後置きする関数宣言に用いる。 |
また、戻り値型を後置きする関数宣言に用いる。 |
||
< |
<syntaxhighlight lang="cpp"> |
||
// 以下の2つは同じ宣言。 |
// 以下の2つは同じ宣言。 |
||
int main(int argc, char** argv); |
int main(int argc, char** argv); |
||
auto main(int argc, char** argv) -> int; |
auto main(int argc, char** argv) -> int; |
||
</syntaxhighlight> |
|||
</source> |
|||
=== 複合型 === |
=== 複合型 === |
||
65行目: | 65行目: | ||
{{Main|const}} |
{{Main|const}} |
||
Cの書き換え不能という意味に加え、定数の意味が加わっている。具体的にはCと違いブロックスコープにない場合、定数扱いとなり、[[extern]]を指定しない限り内部結合になる。[[プリプロセッサ]]による[[マクロ (コンピュータ用語)|マクロ]]の代替的手段になる。 |
Cの書き換え不能という意味に加え、定数の意味が加わっている。具体的にはCと違いブロックスコープにない場合、定数扱いとなり、[[extern]]を指定しない限り内部結合になる。[[プリプロセッサ]]による[[マクロ (コンピュータ用語)|マクロ]]の代替的手段になる。 |
||
< |
<syntaxhighlight lang="cpp"> |
||
const int N = 16; |
const int N = 16; |
||
int Array[N]; |
int Array[N]; |
||
</syntaxhighlight> |
|||
</source> |
|||
このコード片で、Cでは<code>N</code>が定数ではないので<code>Array</code>の宣言はエラーになる。C99でも[[グローバル変数]]は[[可変長配列]]にできないのでやはりエラーになる。 |
このコード片で、Cでは<code>N</code>が定数ではないので<code>Array</code>の宣言はエラーになる。C99でも[[グローバル変数]]は[[可変長配列]]にできないのでやはりエラーになる。 |
||
クラス内では、[[整数型]]を<code>static const</code>で修飾すると[[スコープ|クラススコープ]]の定数の定義になる。詳しくは[[#static|static]]を参照のこと。 |
クラス内では、[[整数型]]を<code>static const</code>で修飾すると[[スコープ|クラススコープ]]の定数の定義になる。詳しくは[[#static|static]]を参照のこと。 |
||
94行目: | 94行目: | ||
C++では名前(関数名や変数名など)に対して多重定義や名前空間、型安全の保障などの都合から、多くのコンパイラは[[名前修飾]]を施しCとは異なった名前をリンカに対して用いている。その名前の修飾の仕方を指定するのがリンケージ指定である。少なくとも"C"と"C++"の2種類のリンケージが使用できる。何も指定しないと"C++"になる。"C"リンケージでは名前の変形を抑止しCと互換の名前をリンカに対して用いることを意味する。これによりCとC++を混在させてプログラムを作るときに使われる。 |
C++では名前(関数名や変数名など)に対して多重定義や名前空間、型安全の保障などの都合から、多くのコンパイラは[[名前修飾]]を施しCとは異なった名前をリンカに対して用いている。その名前の修飾の仕方を指定するのがリンケージ指定である。少なくとも"C"と"C++"の2種類のリンケージが使用できる。何も指定しないと"C++"になる。"C"リンケージでは名前の変形を抑止しCと互換の名前をリンカに対して用いることを意味する。これによりCとC++を混在させてプログラムを作るときに使われる。 |
||
< |
<syntaxhighlight lang="cpp"> |
||
//a.cpp |
//a.cpp |
||
extern "C" { |
extern "C" { |
||
111行目: | 111行目: | ||
/* ~ */ |
/* ~ */ |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
また、<code>extern template</code>の形でテンプレート実体化宣言を修飾して、外部で実体化されたテンプレートを指定する(*)。 |
また、<code>extern template</code>の形でテンプレート実体化宣言を修飾して、外部で実体化されたテンプレートを指定する(*)。 |
||
126行目: | 126行目: | ||
*整数型にconstと共に指定し宣言と同時に初期化した場合。クラススコープの定数となる。 |
*整数型にconstと共に指定し宣言と同時に初期化した場合。クラススコープの定数となる。 |
||
*クラスの[[メソッド (計算機科学)#静的メソッド|静的メンバ関数]]の場合。(クラス宣言とは別にソースファイルで定義をしてもよいし、クラス内にインラインで定義してもよい) |
*クラスの[[メソッド (計算機科学)#静的メソッド|静的メンバ関数]]の場合。(クラス宣言とは別にソースファイルで定義をしてもよいし、クラス内にインラインで定義してもよい) |
||
< |
<syntaxhighlight lang="cpp"> |
||
//ヘッダbar.h |
//ヘッダbar.h |
||
class bar |
class bar |
||
137行目: | 137行目: | ||
static void g() { /* ~ */ } //OK 静的メンバ g の宣言と定義 |
static void g() { /* ~ */ } //OK 静的メンバ g の宣言と定義 |
||
}; |
}; |
||
</syntaxhighlight> |
|||
</source> |
|||
< |
<syntaxhighlight lang="cpp"> |
||
//ソースbar.cpp |
//ソースbar.cpp |
||
#include "bar.h" |
#include "bar.h" |
||
153行目: | 153行目: | ||
/* ... */ |
/* ... */ |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
古いC++処理系では[[整数型]]を<code>static const</code>で修飾することによる定数の定義ができなかったので、代わりにクラス内の[[列挙型|列挙]] (enum) で代用をすることがしばしばあった。これはenumハックと呼ばれる。 |
古いC++処理系では[[整数型]]を<code>static const</code>で修飾することによる定数の定義ができなかったので、代わりにクラス内の[[列挙型|列挙]] (enum) で代用をすることがしばしばあった。これはenumハックと呼ばれる。 |
||
197行目: | 197行目: | ||
[[キーワード (Java)#修飾子|Java]]などとは違い個々の宣言に付けるものではなく、見た目には関数内でラベルを指定するのと似ている。1度指定すると他の指定がなされるか、クラスの宣言が終わるまでは指定した制御が続く。 |
[[キーワード (Java)#修飾子|Java]]などとは違い個々の宣言に付けるものではなく、見た目には関数内でラベルを指定するのと似ている。1度指定すると他の指定がなされるか、クラスの宣言が終わるまでは指定した制御が続く。 |
||
< |
<syntaxhighlight lang="cpp"> |
||
class foo |
class foo |
||
{ |
{ |
||
210行目: | 210行目: | ||
void setN(int); //protectedになる |
void setN(int); //protectedになる |
||
}; //クラス宣言の終わりには ; が必要。 |
}; //クラス宣言の終わりには ; が必要。 |
||
</syntaxhighlight> |
|||
</source> |
|||
< |
<syntaxhighlight lang="cpp"> |
||
class hoge : private foo //private継承 外部からはhogeのインスタンスを通じてfooのメンバにはアクセスできない。 |
class hoge : private foo //private継承 外部からはhogeのインスタンスを通じてfooのメンバにはアクセスできない。 |
||
{ |
{ |
||
220行目: | 220行目: | ||
~hoge(); |
~hoge(); |
||
}; |
}; |
||
</syntaxhighlight> |
|||
</source> |
|||
=== その他 === |
=== その他 === |
||
332行目: | 332行目: | ||
関数に例外指定を付与する。 |
関数に例外指定を付与する。 |
||
< |
<syntaxhighlight lang="cpp"> |
||
//noexceptはどんな例外も投げないことを示す。 |
//noexceptはどんな例外も投げないことを示す。 |
||
int func2() noexcept; |
int func2() noexcept; |
||
350行目: | 350行目: | ||
//この関数から投げられる例外はstd::exception型(とその派生クラス型)かint型しかありえないことを示す。この用法は非推奨。 |
//この関数から投げられる例外はstd::exception型(とその派生クラス型)かint型しかありえないことを示す。この用法は非推奨。 |
||
int func7() throw(std::exception, int) {/* ~ */} |
int func7() throw(std::exception, int) {/* ~ */} |
||
</syntaxhighlight> |
|||
</source> |
|||
C++11以降は、throwを用いた例外指定は推奨されない。C++03以前でも、throwを用いた例外指定は[[例外安全]]のうち例外を投げない表明としてfunc5のように型を無指定にして用いられる場合が大半であった。 |
C++11以降は、throwを用いた例外指定は推奨されない。C++03以前でも、throwを用いた例外指定は[[例外安全]]のうち例外を投げない表明としてfunc5のように型を無指定にして用いられる場合が大半であった。 |
||
また、noexceptは例外指定の有無を判定する式としても用いられる。 |
また、noexceptは例外指定の有無を判定する式としても用いられる。 |
||
< |
<syntaxhighlight lang="cpp"> |
||
//b2はtrue |
//b2はtrue |
||
bool b2 = noexcept(func2()+1); |
bool b2 = noexcept(func2()+1); |
||
//b4はfalse |
//b4はfalse |
||
bool b4 = noexcept(func4()+func7()); |
bool b4 = noexcept(func4()+func7()); |
||
</syntaxhighlight> |
|||
</source> |
|||
===表明=== |
===表明=== |
||
====static_assert (*)==== |
====static_assert (*)==== |
||
コンパイル時に評価される[[表明]]を記述する。検査式が偽になると、指定されたメッセージを伴ってコンパイルエラーとなる。宣言として扱われるが、プログラムの動作には影響がない。 |
コンパイル時に評価される[[表明]]を記述する。検査式が偽になると、指定されたメッセージを伴ってコンパイルエラーとなる。宣言として扱われるが、プログラムの動作には影響がない。 |
||
< |
<syntaxhighlight lang="cpp"> |
||
static_assert(sizeof(bar)==4, "barのサイズが4ではありません"); |
static_assert(sizeof(bar)==4, "barのサイズが4ではありません"); |
||
</syntaxhighlight> |
|||
</source> |
|||
== テンプレートに関するキーワード == |
== テンプレートに関するキーワード == |
||
378行目: | 378行目: | ||
#テンプレート引数で型を引数にとることを示すことに使う(classで代用可能)。 |
#テンプレート引数で型を引数にとることを示すことに使う(classで代用可能)。 |
||
#続く識別子が型名であることを示す。 |
#続く識別子が型名であることを示す。 |
||
< |
<syntaxhighlight lang="cpp"> |
||
//typenameの例 |
//typenameの例 |
||
template <typename T> struct s1 //1の用法 |
template <typename T> struct s1 //1の用法 |
||
386行目: | 386行目: | ||
} |
} |
||
}; |
}; |
||
</syntaxhighlight> |
|||
</source> |
|||
用法2.はなぜ存在するのかというと、曖昧性が生じさせないためである。 |
用法2.はなぜ存在するのかというと、曖昧性が生じさせないためである。 |
||
たとえばs1に次のようなクラスをテンプレート引数に渡すとする。 |
たとえばs1に次のようなクラスをテンプレート引数に渡すとする。 |
||
< |
<syntaxhighlight lang="cpp"> |
||
struct s2 |
struct s2 |
||
{ |
{ |
||
static const int type = 0; |
static const int type = 0; |
||
}; |
}; |
||
</syntaxhighlight> |
|||
</source> |
|||
すると、仮にtypenameがなければs1<s2>::fの中の文はs2::type *ptr;となる。これはs2::typeとptrの乗算式と見られるので、構文としては正当なC++の式となってしまう(ただしこの例ではptrが宣言されていないためコンパイルエラーになる)。そうならないように、曖昧性を排除するために型名である場合はtypenameを先行させる仕様になっている。 |
すると、仮にtypenameがなければs1<s2>::fの中の文はs2::type *ptr;となる。これはs2::typeとptrの乗算式と見られるので、構文としては正当なC++の式となってしまう(ただしこの例ではptrが宣言されていないためコンパイルエラーになる)。そうならないように、曖昧性を排除するために型名である場合はtypenameを先行させる仕様になっている。 |
||
2020年7月5日 (日) 22:43時点における版
キーワード (C++)は、プログラミング言語の1つであるC++のキーワード(予約語を参照)に関する説明。この項目は、プログラムの細かい説明には立ち入らず、他の言語と比較できるような説明を目的としている。
C++のキーワードの特徴
C++11には86のキーワードがある。最初に制定された規格であるC++98では73のキーワードが採用され、C++11で新たに13のキーワードおよび2つの文脈依存のキーワード(後述)が追加された。C++11から追加のキーワード及び機能には(*)を付す。C++14およびC++17ではキーワードは増えていない。
C89で存在したキーワードは、すべてがほぼそのままの形で取り入れられている。中には、inline
など最初C++98に導入されたキーワードが後からC99にも導入されたものもある。alignof
は C11/C++11 両方に追加された。
値に関するキーワード
nullptr (*)
Nullポインタ (null pointer) を表す。この値はあるstd::nullptr_t
型のオブジェクトで、任意のポインタ型のNullポインタ値に暗黙変換できるが、整数リテラル0
に置換される従来のNULL
マクロとは異なり、整数型には暗黙変換できない。
型に関するキーワード
複数のキーワードを組み合わせることで意味が変わるものが多い(文脈依存のキーワード)。
基本型
int, long, short, signed, unsigned
short
単体では符号付き短整数型signed short int
を、long
単体では符号付き長整数型signed long int
を意味する。long long int
は少なくとも64ビットの精度を持つ整数型である(*)。
float, double
long double
は少なくともdouble
と同じ精度を持つ浮動小数点数型。処理系によっては拡張倍精度浮動小数点数型となる。
bool, true, false
C99ではマクロで定義されており[1]キーワードではないが、C++ではキーワードである。
char, wchar_t, char16_t (*), char32_t (*)
wchar_t
は、Cではキーワードでないが、C++ではキーワードである。
char16_t
とchar32_t
は、それぞれUTF-16およびUTF-32の文字を格納するための整数型を表す。
void
- 戻り値や引数がないことを表す型。
- デリファレンスする先の型を指定しないポインタ
void*
の表現に用いられる。
auto (*)
変数宣言の際に型として指定すると、初期化式から型推論を行う。
また、戻り値型を後置きする関数宣言に用いる。
// 以下の2つは同じ宣言。
int main(int argc, char** argv);
auto main(int argc, char** argv) -> int;
複合型
class, struct, union
C++においてstruct
はデフォルトのアクセス制御がpublic
であること以外はclass
と全く同じである。union
もクラスの一種という扱いである。
union
はすべてのメンバ変数が同一メモリ領域を共有するのはCのままであるが、class
に準じてメンバ関数を持てるようになっている。
規格では、クラス内で宣言した変数および関数は、それぞれデータメンバーおよびメンバ関数と呼ぶ。JavaやC#のように、フィールド・メソッドなどといった用語は使われない。
enum
enum
単独ではスコープのない列挙型を意味する。enum class
、enum struct
の形で、スコープ付きの列挙型の宣言に使用する(*)。
型修飾子
const
Cの書き換え不能という意味に加え、定数の意味が加わっている。具体的にはCと違いブロックスコープにない場合、定数扱いとなり、externを指定しない限り内部結合になる。プリプロセッサによるマクロの代替的手段になる。
const int N = 16;
int Array[N];
このコード片で、CではN
が定数ではないのでArray
の宣言はエラーになる。C99でもグローバル変数は可変長配列にできないのでやはりエラーになる。
クラス内では、整数型をstatic const
で修飾するとクラススコープの定数の定義になる。詳しくはstaticを参照のこと。
volatile
volatileの指定された記憶領域は、実行しているコードが書き換えを行わない場合にも、何らかの理由で内容が書き換えられる可能性を持つ。書き換えの起きる具体的な要因としては、何らかのハードウェアによる書き換えが挙げられる。
コンパイラによる最適化では、メモリを書き換えない限り内容が変わらないことを利用し、メモリからの再読み込みの省略などを行うが、例えばあるメモリ領域にハードウェアが書き込んでいて、そのメモリ領域の変化を読み取りループで監視しようとするならば、volatile指定が無い場合はコンパイラが「書き込みを行っていないのでメモリ内容が変化する可能性は無い」と判断し、ループを消し去ったり、メモリを再読み込みせずに単純な無限ループを行ったりするなど、期待と異なる最適化を行う可能性が高い。そのような場合、volatileを適切に指定することで、メモリ領域を正しくポーリングすることが期待できる。
また、コンパイラによっては、volatileの指定された記憶領域へのアクセス前後において、適切なメモリバリアを自動的に配置することもある。が、逆にメモリバリアについては一切関知しないものもあるため、ノンブロッキング同期プログラミングなどでは特別な注意が必要となる。
ハードウェアに近い操作を行う処理を記述する際は、特に重要になる修飾子である。
記憶クラス指定子
(auto:C++03まで)
C++03以前では自動変数を意味する記憶クラス指定子であったが、C++11で廃止され、全く別の機能が割り当てられた。
関数内で定義した変数はデフォルトで自動変数となるため、C++03以前においても記憶クラス指定子としてのauto
を用いる必要は全くない。前方互換性のためにも無意味に使用すべきではない。なお、記憶クラスを指定しない変数の記憶クラスのを表す用語としては「自動変数」(auto変数)のままで変更はない。
extern
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
の形でテンプレート実体化宣言を修飾して、外部で実体化されたテンプレートを指定する(*)。
register
C++17以降では何の機能もないキーワードである。将来のために予約されている。
C++14以前では、特にレジスタに割り当ててほしい自動変数に指定する記憶クラス指定子であった。Cよりも意味合いが弱く、Cのregister変数はアドレス参照(&
演算子によるポインタ取得)を行えないが、C++では行えた。つまり、register変数として宣言してもメモリに配置されうる。コンパイラが高度な最適化を行う場合、レジスタに配置すべき変数の判断はコンパイラの方が適切に行えることが多いので、C++14以前のコンパイラでも、この指定を無視するのが一般的であった。
static
- ファイルスコープの指定(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; //NG 整数型でない
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
を併用することで、クラス宣言部で定数定義できる型が増加した[2]。
mutable
- constなオブジェクトでも書き換え可能にしたいクラスメンバ変数に指定する。
- ラムダ式を修飾して、コピーキャプチャした変数の書き換えを許可する(*)。
thread_local (*)
グローバル変数やクラス・関数内静的変数について、スレッドローカルな記憶域に確保するよう指示する。
宣言指定子
friend
フレンド関数・フレンドクラスの宣言に用いる。
typedef
関数指定子
constexpr (*)
定数式を表す。変数や関数を修飾して、コンパイル時定数となりうることを指示する。
explicit
inline
- 関数指示子に使用することで、関数をインライン展開するためのヒントをコンパイラに与える。クラスの宣言内で関数を定義した場合は、inlineの有無にかかわらずinlineが指定されたものとして取り扱われる。
inline namespace
の形で透過的な名前空間の宣言に用いる。透過的な名前空間の名前は、名前空間名で修飾しなくても使えるようになる(*)。
virtual
- 仮想関数を宣言する。C++ではこれを明示しないと派生クラスでポリモーフィックにオーバーライドすることはできない。派生クラスではオーバーライドするときに特に何か指定する必要はないが、virtualを省略しないスタイルも一般的である。
- 仮想継承するときにベースクラスの指定に修飾する。
クラスに関するキーワード
アクセス制御
public, protected, private
クラスメンバと継承のアクセス制御に用いられる。
- 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();
};
その他
operator
- 演算子多重定義(オペレータオーバーロード)の関数を定義するのに用いる。
- 自分のクラスから他の型へ、暗黙の型変換を行う関数を定義するのに用いる。なお、他の型から自分のクラスへの変換は1引数のコンストラクタを使用する。
- ユーザー定義リテラルの定義に用いる。
operator"" suffix
は接尾辞suffix
で記述するユーザー定義リテラルを定義する関数名である(*)。
this
自分自身へのポインタ。当然ながらクラスの非静的メンバ関数内でのみ使用できる。参照でなくポインタである理由は、thisがC++に導入された当時まだ参照がなかったからである [3] 。
文に関するキーワード
制御構造
if, else
for
while, do
switch, case, default
defaultは関数の定義にも用いる。特殊メンバ関数を「= default
」の形で定義して、コンパイラ生成のものを使用することを明示する(*)。
break
continue
goto
return
try, catch
式に関するキーワード
動的記憶域確保
new, delete
newはヒープにオブジェクトを割り当てるnewとnew[]演算子に用いられ、deleteはそれを開放する演算子 deleteとdelete[]に用いられる([]の有無で演算子は区別される)。JavaやC#などと違い、C++はガベージコレクションをもたないのでオブジェクトが不要になったら自分でdeleteを呼ぶ必要がある(スマートポインタを用いてdeleteの手間を省くようにすることはできる)。もっとも、C++には自動変数・大域変数などが存在するため、それほどnewは多用されない。
deleteは関数の定義にも使用される。関数を「= delete
」の形で定義して、そのシグネチャの関数を存在させないことを指示する(*)。
型変換
型変換(キャスト)は注意を要する操作であるにもかかわらず、Cの型変換演算子はあまりにも目立たず、目的がコードから見えにくいという理由からC++では、型変換を行う場合には用途ごとの4つの型変換演算子を用いることが推奨されている。
dynamic_cast
動的キャスト。RTTIを用いて、目的の型に変換できるかどうかを確認し、不可能であればポインタの場合Nullポインタを返し、参照の場合はbad_cast例外を投げる。また、Cに無い概念の為、Cの型変換演算子で代用できない。
static_cast
静的キャスト。コンパイル時に型チェックを行う。変換前の型から変換後の型へ、あるいはその逆向きの暗黙の変換が存在する場合に変換可能である。変換できなければコンパイルエラーになる。
const_cast
const/volatile性を取り除く場合に用いるキャストである。他のキャストでconst/volatile性が失われる変換はできない。
reinterpret_cast
安全でなかったり移植性のない型変換に用いる。無関係なポインタ型同士の変換や、ポインタと整数型の変換などがそうである。
式に関する情報
alignof (*)
型のアライメントの値を得る。
decltype (*)
式から型を取得し、型名として用いる。
sizeof
型、あるいは式の型のサイズを得る。
また、sizeof...
の形で、可変長引数テンプレートの可変長引数部の長さを取得する(*)。
typeid
例外処理
throw
例外を投げる。また、後述の例外指定の用法もある(C++11以降でこの用法は非推奨)。
noexcept (*)
関数に例外指定を付与する。
//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 (*)
コンパイル時に評価される表明を記述する。検査式が偽になると、指定されたメッセージを伴ってコンパイルエラーとなる。宣言として扱われるが、プログラムの動作には影響がない。
static_assert(sizeof(bar)==4, "barのサイズが4ではありません");
テンプレートに関するキーワード
template
- クラステンプレート・関数テンプレートの宣言あるいは定義。特殊化や部分特殊化にも使う。
- クラステンプレート・関数テンプレートの明示的実体化。
- メンバテンプレートをテンプレート引数を明示して使用する場合にはこれを先行しなければならない。理由はテンプレート引数の < > と不等号演算子との区別をつけるためである。
typename
- テンプレート引数で型を引数にとることを示すことに使う(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を先行させる仕様になっている。
export
C++11では何の機能もないキーワードである。将来のために予約されている(*)。
C++03以前では、分離コンパイルを行うクラス・関数テンプレートに指定するものであった。分離コンパイルとは、通常の関数などのようにヘッダに宣言を書いて、どこかのソースファイルに定義を書く形式のことである。これを指定しないとテンプレートは通常ヘッダに定義を書く必要がある。
このキーワードに対応しているコンパイラは、一般に広く知られたものではComeau C++のみである[4]。対応しない多くのコンパイラでは、このキーワードは単に無視されるか、キーワードとして扱われない場合さえある。
名前空間に関するキーワード
namespace
- 名前空間の宣言 (namespace NS { /* ~ */ })
- 名前空間は入れ子にすることができる。
- 名前空間名を省略すると無名名前空間の宣言になる。無名名前空間の中にある宣言は他の翻訳単位から見えない。
- usingディレクティブ(usingを参照)
- 名前空間のエイリアス (namespace NS2 = NS;)
using
- using宣言 (using NS::NAME;)
- usingディレクティブ (using namespace NS;)
- アクセス宣言 - public, protected, privateのclass Hogeの例を参照。
- テンプレートの別名を定義する(*)。
インラインアセンブラ
asm
asm(文字列リテラル)
という構文が定まっているだけで、その文字列リテラルの書式等は処理系依存である。多くのコンパイラではインラインアセンブラを利用するために用いる。
アトリビュート
alignas (*)
変数宣言を修飾するアトリビュートで、変数のアライメントを指定する。
文脈依存のキーワード(*)
文脈依存のキーワード(contextual keyword)は、ソースコード中の特定の位置に現れた場合にのみキーワードとして扱われ、それ以外の箇所では単なる識別子として扱われる(変数名や関数名として使用出来る)。C++11から新たに追加された。
final
メンバ関数の宣言の直後、またはクラス宣言のクラス名の直後において文脈依存のキーワードとして扱われる。メンバ関数の宣言の直後では、その関数がオーバーライドされることを禁止する。クラス名の直後では、そのクラスから派生すること(基底クラスとして用いられること)を禁止する。
override
メンバ関数の宣言の直後において文脈依存のキーワードとして扱われる。仮想関数が基底クラスのメンバ関数をオーバーライドすることを明示する。
代替表現
代替字句(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
- ^=
C言語のキーワードのうち、C++ではキーワードでないもの
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++20で予定されている変更
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は実行時チェックを意図しないものに指定することを規格では意図している。実際にどの契約レベルまで実行時にチェックするかは、「ビルドレベル」によって変更される。
脚注
- ^ C99の
bool
はtypedefではなくマクロで定義されることが規格で規定されている。 - ^ 静的メンバ - 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)