予約語 (C++)

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動: 案内, 検索

予約語(よやくご)(C++)は、プログラミング言語の1つであるC++予約語に関する説明。この項目は、プログラムの細かい説明には立ち入らず、他の言語の予約語と比較できるような説明を目的としている。

目次

[編集] C++の予約語の特徴

C++ には86の予約語がある。最初に制定された規格であるC++98では73の予約語が採用され、C++11で新たに13の予約語および2つの文脈依存の予約語(後述)が追加された。C++11から追加の予約語及び機能には(*)を付す。

C89/C95で存在した予約語は、すべてがほぼそのままの形で取り入れられている。中には、inlineなど最初C++に導入された予約語が後からCにも導入されたものもある。

[編集] 値に関する予約語

[編集] nullptr(*)

Nullポインタを表す。この値はあるstd::nullptr_t型のオブジェクトで、任意のポインタ型のNullポインタ値に暗黙変換できるが、0とは異なり整数型には暗黙変換できない。

[編集] 型に関する予約語

[編集] 基本型

[編集] int, long, short, signed, unsigned

longは、long doubleとしても用いられる。long long intは少なくとも64ビットの精度を持つ整数型である(*)。

[編集] float, double

[編集] bool, true, false

C99ではマクロあるいはtypedefで作られており予約語ではないが、C++では予約語である。

[編集] char, wchar_t, char16_t(*), char32_t(*)

wchar_tは、Cでは予約語でないが、C++では予約語である。 char16_tchar32_tは、それぞれUTF-16およびUTF-32の文字を格納するための整数型を表す。

[編集] void

  1. 戻り値や引数がないことを表す型。
  2. 逆参照する先の型を指定しないポインタvoid*の表現に用いられる。

[編集] auto(*)

変数宣言の際に型として指定すると、初期化式から型推論を行う。

また、戻り値型を後置きする関数宣言に用いる。

//以下の2つは同じ宣言。
int main(int argc, char** argv);
auto main(int argc, char** argv) -> int ;

[編集] 複合型

[編集] class, struct, union

structとunionは一見クラスとは別物に思われるが、C++ではstructはデフォルトのアクセス制御がpublicであること以外はclassと全く同じである。unionも標準規格(ISO/IEC 14882:2003やJIS X 3014:2003 (C++)など)ではクラスの一種という扱いである。

unionはすべてのメンバ変数が同一メモリ領域を共有するのはCのままであるが、classに準じてメンバ関数を持てるようになっている。一方で、PODでない型をメンバ変数に持てない、コンストラクタデストラクタを持てないなどの制限がある。

クラス内で宣言した変数・関数は、データメンバーメンバ関数と呼ぶ。フィールド・メソッドなどといった言葉は用いない。

[編集] enum

enum単独ではスコープのない列挙型を意味する。enum classenum 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よりも意味合いが弱まっている。

Cのregister変数はアドレス参照(&演算子によるポインタ取得)を行えないが、C++では行える。つまり、register変数として宣言してもメモリに配置されうる。

コンパイラが高度な最適化を行う場合、レジスタに配置すべき変数の判断はコンパイラの方が適切に行えることが多いので、現在のコンパイラはこの指定を無視するのが一般的である。C++11においてはdeprecated(推奨しない機能)とされ、将来の規格では削除される可能性がある。

[編集] 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ハックと呼ばれる。

[編集] mutable

  1. constなオブジェクトでも書き換え可能にしたいクラスメンバ変数に指定する。
  2. ラムダ式を修飾して、コピーキャプチャした変数の書き換えを許可する(*)。

[編集] thread_local(*)

グローバル変数やクラス・関数内静的変数について、スレッドローカルな記憶域に確保するよう指示する。

[編集] 宣言指定子

[編集] friend

フレンド関数・フレンドクラスの宣言に用いる。

[編集] typedef

[編集] 関数指定子

[編集] constexpr(*)

変数や関数を修飾して、コンパイル時定数となりうることを指示する。

[編集] explicit

  1. コンストラクタに指定して暗黙の型変換に用いないことを指定する。
  2. 変換関数を修飾して、暗黙の型変換に用いないことを指定する(*)。

[編集] inline

  1. 関数指示子に使用することで、関数をインライン展開するためのヒントをコンパイラに与える。クラスの宣言内で関数を定義した場合は、inlineの有無にかかわらずinlineが指定されたものとして取り扱われる。
  2. inline namespaceの形で透過的な名前空間の宣言に用いる。透過的な名前空間の名前は、名前空間名で修飾しなくても使えるようになる(*)。

[編集] virtual

  1. 仮想関数を宣言する。C++ではこれを明示しないと派生クラスでポリモーフィックオーバーライドすることはできない。派生クラスではオーバーライドするときに特に何か指定する必要はないが、virtualを省略しないスタイルも一般的である。
  2. 仮想継承するときにベースクラスの指定に修飾する。

[編集] クラスに関する予約語

[編集] アクセス制御

[編集] 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. 演算子多重定義(オペレータオーバーロード)の関数を定義するのに用いる。
  2. 自分のクラスから他の型へ、暗黙の型変換を行う関数を定義するのに用いる。なお、他の型から自分のクラスへの変換は1引数のコンストラクタを使用する。
  3. ユーザー定義リテラルの定義に用いる。operator"" _FOOは接尾辞_FOOで記述するユーザー定義リテラルを定義する関数名である(*)。

[編集] this

自分自身へのポインタ。当然ながらクラスの非静的メンバ関数内でのみ使用できる。参照でなくポインタである理由は、thisがC++に導入された当時まだ参照がなかったからである [1]

[編集] 文に関する予約語

[編集] 制御構造

[編集] 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

  1. クラステンプレート・関数テンプレートの宣言あるいは定義。特殊化や部分特殊化にも使う。
  2. クラステンプレート・関数テンプレートの明示的実体化。
  3. メンバテンプレートをテンプレート引数を明示して使用する場合にはこれを先行しなければならない。理由はテンプレート引数の < > と不等号演算子との区別をつけるためである。

[編集] typename

  1. テンプレート引数で型を引数にとることを示すことに使う(classで代用可能)。
  2. 続く識別子が型名であることを示す。
//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++のみである[2]。対応しない多くのコンパイラでは、この予約語は単に無視されるか、予約語として扱われない場合さえある。

[編集] 名前空間に関する予約語

[編集] namespace

  1. 名前空間の宣言 (namespace NS { /* ~ */ })
    • 名前空間は入れ子にすることができる。
    • 名前空間名を省略すると無名名前空間の宣言になる。無名名前空間の中にある宣言は他の翻訳単位から見えない。
  2. usingディレクティブ(usingを参照)
  3. 名前空間のエイリアス (namespace NS2 = NS;)

[編集] using

  1. using宣言 (using NS::NAME;)
  2. usingディレクティブ (using namespace NS;)
  3. アクセス宣言 - public, protected, privateのclass Hogeの例を参照。
  4. テンプレートの別名を定義する(*)。

[編集] 代替表記に関する予約語

C/C++ではASCIIの記号類を多用しているので、ISO/IEC 646のUS以外を使用している環境ではこれらの記号の含まれたソースコードは正常に読み取れないことがある(ただし文字化けとは異なる)。それらの代用として、問題のない文字だけで表現するのがこの代替表記である。トライグラフダイグラフも併せて用いられる。これらはCではすべてヘッダ<iso646.h>でマクロによって実装されているが、C++では予約語である(C++では<iso616.h>と<ciso646>の内容は空である)。

以下にそれぞれ対応する演算子を示してある。

and
&&
and_eq
&=
bitand
&
bitor
|
compl
~
not
!
not_eq
!=
or
||
or_eq
|=
xor
^
xor_eq
^=

[編集] インラインアセンブラ

[編集] asm

asm(文字列リテラル)という構文が定まっているだけで、その文字列リテラルの書式等は処理系依存である。多くのコンパイラではインラインアセンブラを利用するために用いる。

[編集] アトリビュート

[編集] alignas(*)

変数宣言を修飾するアトリビュートで、変数のアライメントを指定する。

[編集] 文脈依存の予約語(*)

文脈依存の予約語(contextual keyword)は、ソースコード中の特定の位置に現れた場合にのみ予約語として扱われ、それ以外の箇所では単なる識別子として扱われる(変数名や関数名として使用出来る)。C++11から新たに追加された。

[編集] final

メンバ関数の宣言の直後、またはクラス宣言のクラス名の直後において文脈依存の予約語として扱われる。メンバ関数の宣言の直後では、その関数がオーバーライドされることを禁止する。クラス名の直後では、そのクラスから派生すること(基底クラスとして用いられること)を禁止する。

[編集] override

メンバ関数の宣言の直後において文脈依存の予約語として扱われる。仮想関数が基底クラスのメンバ関数をオーバーライドすることを明示する。

[編集] C99の予約語のうち、C++では予約語でないもの

_Bool, _Complex, _Imaginary, restrictはC++の予約語ではない。C99の_BoolにはC++のboolが対応する。また、_Complexに関しては、代わりにstd::complexクラステンプレートが標準C++ライブラリに存在する。

[編集] 脚注

  1. ^ Stroustrup, Bjarne  (1994年). The Design and Evolution of C++. Addison-Wesley, p. 2.5.2. ISBN 0-201-54330-3. 
    (日本語訳: C++の設計と進化ソフトバンクパブリッシング、2005年。ISBN 4-7973-2854-1
  2. ^ [1]

[編集] 参考文献

[編集] 関連項目

個人用ツール
名前空間
変種
操作
案内
ヘルプ
ツールボックス