スコープ
C++プログラムに現れるそれぞれの宣言は、互いに連続しない可能性のある特定のスコープでのみ可視です。
スコープ内では、非修飾名探索を使用して、名前をその宣言に関連付けることができます。
目次 |
[編集] 一般
各プログラムには、プログラム全体を含むグローバルスコープがあります。
その他のスコープSは、以下のいずれかによって導入されます。
| (C++26以降) |
Sは常に別のスコープ内に現れ、そのスコープはSを含みます。
プログラム点における囲むスコープとは、そのプログラム点を含む任意のスコープです。そのようなスコープのうち最小のものを、その点における即時スコープと呼びます。
あるスコープが、プログラム点PとスコープS(Pを含まない)の間に介在するとは、そのスコープがSであるかSを含むが、Pは含まない場合をいいます。
テンプレート仮引数スコープではない任意のスコープSの親スコープは、Sを含み、かつテンプレート仮引数スコープではない最小のスコープです。
特に指定がない限り
- 宣言は、その場所における即時スコープを占めます。
- 宣言の対象スコープとは、それが占めるスコープです。
- 宣言によって(再)導入されるすべての名前は、その対象スコープにおいて宣言に結合されます。
エンティティがスコープSに属するとは、Sがそのエンティティの宣言の対象スコープである場合をいいます。
// global scope scope // scope S T int x; // ─┐ // program point X // │ { // │ ─┐ { // │ │ ─┐ int y; // │ │ │ // program point Y } // │ │ ─┘ } // ─┘ ─┘
上記のプログラムでは
- グローバルスコープ、スコープ
S、およびスコープTはプログラム点Yを含みます。
- 言い換えれば、これら3つのスコープはすべて、プログラム点
Yにおける囲むスコープです。
- 言い換えれば、これら3つのスコープはすべて、プログラム点
- グローバルスコープはスコープ
SとTを含み、スコープSはスコープTを含みます。
- したがって、スコープ
Tは3つすべてのスコープの中で最小であり、これは次のことを意味します。
- スコープ
Tは、プログラム点Yにおける即時スコープです。 - 変数yの宣言は、その場所においてスコープ
Tを占めます。 - スコープ
Tは、yの宣言の対象スコープです。 - 変数yはスコープ
Tに属します。
- スコープ
- スコープ
SはスコープTの親スコープであり、グローバルスコープはスコープSの親スコープです。
- したがって、スコープ
- スコープ
Sは、プログラム点XとスコープTの間に介在します。
[編集] ブロックスコープ
各
は、その文またはハンドラを含むブロックスコープを導入します。
ブロックスコープに属する変数はブロック変数です。
int i = 42; int a[10]; for (int i = 0; i < 10; i++) // inner “i” inhabits the block scope a[i] = i; // introduced by the for-statement int j = i; // j = 42
宣言がブロックスコープSを占め、関数を宣言するかextern指定子を使用する場合、その宣言は名前付きモジュールに付属してはならない(C++20以降)、その対象スコープはより大きな囲むスコープ(最も内側の囲む名前空間スコープ)ですが、名前は即時スコープSに結合されます。
名前独立宣言ではない(C++26以降)宣言が、ブロックスコープSの
|
(C++11以降) |
- それ自体が選択文または繰り返し文ではない、選択文または繰り返し文の副文、または
- 関数tryブロックのハンドラ
において名前をブロックスコープSに結合し、その宣言が、対象スコープがSの親スコープである宣言と潜在的に競合する場合、プログラムは不正です。
if (int x = f()) // declares “x” { // the if-block is a substatement of the if-statement int x; // error: redeclaration of “x” } else { // the else-block is also a substatement of the if-statement int x; // error: redeclaration of “x” } void g(int i) { extern int i; // error: redeclaration of “i” }
[編集] 関数仮引数スコープ
各仮引数宣言Pは、Pを含む関数仮引数スコープを導入します。
- 宣言された仮引数が関数宣言の仮引数リストのものである場合
|
(C++11以降) |
|
(C++17以降) |
|
(C++20以降) |
int f(int n) // the declaration of the parameter “n” { // introduces a function parameter scope /* ... */ } // the function parameter scope ends here
ラムダスコープ各ラムダ式は、 ラムダ式Eの初期化子付きキャプチャは、Eによって導入されたラムダスコープを占めます。 auto lambda = [x = 1, y]() // this lambda expression introduces a lambda scope, { // it is the target scope of capture “x” /* ... */ }; // the lambda scope ends before the semicolon |
(C++14以降) |
[編集] 名前空間スコープ
名前空間Nのすべての名前空間定義は、Nのすべての名前空間定義の宣言を含む名前空間スコープSを導入します。
対象スコープがSであるかSに含まれる非フレンドの再宣言または特殊化ごとに、以下の部分もスコープSに含まれます。
- クラス(テンプレート)の再宣言またはクラステンプレートの特殊化の場合、そのクラスヘッダ名より後の部分。
- 列挙の再宣言の場合、その列挙ヘッダ名より後の部分。
- その他の再宣言または特殊化の場合、宣言子の非修飾IDまたは修飾IDより後の部分。
グローバルスコープは、グローバル名前空間の名前空間スコープです。
namespace V // the namespace definition of “V” { // introduces a namespace scope “S” // the first part of scope “S” begins here void f(); // the first part of scope “S” ends here } void V::f() // the portion after “f” is also a part of scope “S” { void h(); // declares V::h } // the second part of scope “S” ends here
[編集] クラススコープ
クラスまたはクラステンプレートCの各宣言は、Cのクラス定義のメンバ仕様を含むクラススコープSを導入します。
対象スコープがSであるかSに含まれる非フレンドの再宣言または特殊化ごとに、以下の部分もスコープSに含まれます。
- クラス(テンプレート)の再宣言またはクラステンプレートの特殊化の場合、そのクラスヘッダ名より後の部分。
- 列挙の再宣言の場合、その列挙ヘッダ名より後の部分。
- その他の再宣言または特殊化の場合、宣言子の非修飾IDまたは修飾IDより後の部分。
class C // the class definition of “C” { // introduces a class scope “S” // the first part of scope “S” begins here void f(); // the first part of scope “S” ends here } void C::f() // the portion after “f” is also a part of scope “S” { /* ... */ } // the second part of scope “S” ends here
[編集] 列挙スコープ
列挙型Eの各宣言は、Eの非不透明(C++11以降)列挙型宣言の列挙子リスト(存在する場合)を含む列挙スコープを導入します。
enum class E // the enumeration declaration of “E” { // introduces an enumeration scope “S” // scope “S” begins here e1, e2, e3 // scope “S” ends here }
[編集] テンプレート仮引数スコープ
各テンプレートテンプレート仮引数は、そのテンプレートテンプレート仮引数全体のテンプレート仮引数リストとrequire句(C++20以降)を含むテンプレート仮引数スコープを導入します。
各テンプレート宣言Dは、Dのテンプレート仮引数リストの先頭からDの終わりまで広がるテンプレート仮引数スコープSを導入します。テンプレート仮引数リストの外側でSを占めるはずの宣言は、代わりにDと同じスコープを占めます。
テンプレート仮引数のみがテンプレート仮引数スコープに属し、テンプレート仮引数スコープのみが親スコープとしてテンプレート仮引数スコープを持ちます。
// the class template declaration of “X” // introduces a template parameter scope “S1” template < // scope “S1” begins here template // the template template parameter “T” // introduces another template parameter scope “S2” < typename T1 typename T2 > requires std::convertible_from<T1, T2> // scope “S2” ends here class T, typename U > class X; // scope “S1” ends before the semicolon namespace N { template <typename T> using A = struct X; // “X” inhabits the same scope as template // declaration, namely the scope of “N” }
契約表明スコープ各契約表明 事後条件表明が名前独立ではない識別子を持ち、かつその事後条件表明が関数funcに関連付けられている場合、対象スコープが以下のいずれかのスコープである宣言
|
(C++26以降) |
[編集] 宣言点
一般に、名前は最初の宣言の場所の後に可視となり、その場所は次のように配置されます。
単純宣言で宣言された名前の場所は、その名前の宣言子の直後であり、もしあればその初期化子の前です。
int x = 32; // outer x is in scope { int x = x; // inner x is in scope before the initializer (= x) // this does not initialize inner x with the value of outer x (32), // this initializes inner x with its own (indeterminate) value } std::function<int(int)> f = [&](int n){ return n > 1 ? n * f(n - 1) : n; }; // the name of the function f is in scope in the lambda and can // be correctly captured by reference, giving a recursive function
const int x = 2; // outer x is in scope { int x[x] = {}; // inner x is in scope before the initializer (= {}), // but after the declarator (x[x]) // in the declarator, outer x is still in scope // this declares an array of 2 int }
クラスまたはクラステンプレート宣言の場所は、そのクラスヘッダ内にある、クラスに名前を付ける識別子(またはテンプレート特殊化に名前を付けるテンプレートID)の直後です。クラスまたはクラステンプレート名は、基底クラスのリスト内ですでにスコープ内にあります。
struct S: std::enable_shared_from_this<S> {}; // S is in scope at the colon
enum指定子または不透明enum宣言(C++11以降)の場所は、列挙に名前を付ける識別子の直後です。
enum E : int // E is in scope at the colon { A = sizeof(E) };
型エイリアスまたはエイリアステンプレート宣言の場所は、エイリアスが参照する型IDの直後です。
using T = int; // outer T is in scope at the semicolon { using T = T*; // inner T is in scope at the semicolon, // outer T is still in scope before the semicolon // same as T = int* }
コンストラクタに名前を付けないusing宣言内の宣言子の場所は、その宣言子の直後です。
template<int N> class Base { protected: static const int next = N + 1; static const int value = N; }; struct Derived: Base<0>, Base<1>, Base<2> { using Base<0>::next, // next is in scope at the comma Base<next>::value; // Derived::value is 1 };
列挙子の場所は、その定義の直後です(変数とは異なり、初期化子の前ではありません)。
const int x = 12; { enum { x = x + 1, // enumerator x is in scope at the comma, // outer x is in scope before the comma, // enumerator x is initialized to 13 y = x + 1 // y is initialized to 14 }; }
注入クラス名の場所は、そのクラス(またはクラステンプレート)定義の開き波括弧の直後です。
template<typename T> struct Array // : std::enable_shared_from_this<Array> // error: the injected class name is not in scope : std::enable_shared_from_this< Array<T> > // OK: the template-name Array is in scope { // the injected class name Array is now in scope as if a public member name Array* p; // pointer to Array<T> };
|
関数ローカルな事前定義変数__func__の暗黙の宣言の場所は、関数定義の関数本体の直前です。 |
(C++11以降) |
|
構造化束縛宣言の場所は、識別子リストの直後ですが、構造化束縛初期化子は宣言される名前のいずれかを参照することを禁止されています。 |
(C++17以降) |
|
範囲forループの範囲宣言で宣言された変数または構造化束縛(C++17以降)の場所は、範囲式の直後です。 std::vector<int> x; for (auto x : x) // vector x is in scope before the closing parenthesis, // auto x is in scope at the closing parenthesis { // the auto x is in scope } |
(C++11以降) |
テンプレート仮引数の場所は、その完全なテンプレート仮引数(オプションのデフォルト引数を含む)の直後です。
typedef unsigned char T; template< class T = T, // template parameter T is in scope at the comma, // typedef name of unsigned char is in scope before the comma T // template parameter T is in scope N = 0 > struct A { };
|
識別子を持つ事後条件表明の場所は、その |
(C++26以降) |
|
コンセプト定義の場所は、コンセプト名の直後ですが、コンセプト定義は宣言されるコンセプト名を参照することを禁止されています。 |
(C++20以降) |
名前付き名前空間定義の場所は、名前空間名の直後です。
| このセクションは未完成です 理由:[basic.scope.pdecl]の残り |
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 2793 | C++98 | ブロックスコープ内のextern宣言は 親スコープ内の別の宣言と競合する可能性がある |
禁止された |
[編集] 参照
- C++23標準 (ISO/IEC 14882:2024)
- 6.4 Scope [basic.scope]
- C++20 standard (ISO/IEC 14882:2020)
- 6.4 Scope [basic.scope]
- C++17 standard (ISO/IEC 14882:2017)
- 6.3 Scope [basic.scope]
- C++14 standard (ISO/IEC 14882:2014)
- 3.3 Scope [basic.scope]
- C++11 standard (ISO/IEC 14882:2011)
- 3.3 Scope [basic.scope]
- C++98 標準 (ISO/IEC 14882:1998)
- 3.3 Declarative regions and scopes [basic.scope]
[編集] 関連項目
| C言語のドキュメントScope
|