名前空間
変種
操作

スコープ

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

C++プログラムに現れるそれぞれの宣言は、互いに連続しない可能性のある特定のスコープでのみ可視です。

スコープ内では、非修飾名探索を使用して、名前をその宣言に関連付けることができます。

目次

[編集] 一般

各プログラムには、プログラム全体を含むグローバルスコープがあります。

その他のスコープSは、以下のいずれかによって導入されます。

(C++26以降)

Sは常に別のスコープ内に現れ、そのスコープはS含みます

プログラム点における囲むスコープとは、そのプログラム点を含む任意のスコープです。そのようなスコープのうち最小のものを、その点における即時スコープと呼びます。

あるスコープが、プログラム点PとスコープSPを含まない)の間に介在するとは、そのスコープが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における囲むスコープです。
  • グローバルスコープはスコープSTを含み、スコープ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以降)
  • 宣言された仮引数がrequiresの仮引数リストのものである場合、導入されたスコープは{ 要件シーケンス }の終わりまで延長されます。
(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”
}

契約表明スコープ

契約表明Cは、Cを含む契約表明スコープを導入します。

事後条件表明名前独立ではない識別子を持ち、かつその事後条件表明が関数funcに関連付けられている場合、対象スコープが以下のいずれかのスコープである宣言D潜在的に競合すると、プログラムは不正となります。

  • funcの関数仮引数スコープ。
  • Dラムダ式に関連付けられている場合、事前条件表明の最も近い囲むラムダスコープ。
(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以降)

名前付き名前空間定義の場所は、名前空間名の直後です。

[編集] 欠陥報告

以下の動作変更を伴う欠陥報告が、以前に公開された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]

[編集] 関連項目

English 日本語 中文(简体) 中文(繁體)