命名空间
变体
操作

范围

来自 cppreference.com
< cpp‎ | language
 
 
C++ 语言
一般主题
流程控制
条件执行语句
if
迭代语句(循环)
for
范围-for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 指定符
动态异常规范 (直到 C++17*)
noexcept 指定符 (C++11)
异常
命名空间
类型
指定符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储持续时间指定符
初始化
 
 

每个出现在 C++ 程序中的声明仅在某些可能是不连续的范围中可见。

在某个范围内,可以使用非限定名称查找将名称与其声明关联起来。

内容

[编辑] 一般

每个程序都有一个全局范围,它包含整个程序。

每个其他范围S由以下内容引入

S总是出现在另一个范围内,因此该范围包含S

程序点处的封闭范围是任何包含它的范围;最小的范围被称为该点的直接范围

如果某个范围介于程序点P和范围S(不包含P)之间,则该范围是或包含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
  • 换句话说,这三个范围都是程序点Y处的封闭范围。
  • 全局范围包含范围S和范围T,范围S包含范围T
  • 因此,范围T是所有三个范围中最小的范围,这意味着
  • 范围T是程序点Y处的直接范围。
  • 变量y的声明在其位置处位于范围T
  • 范围Ty声明的目标范围。
  • 变量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

块作用域的 extern 声明目标于更大的封闭作用域,但在其直接作用域中绑定名称。

如果一个声明 不是 与名称无关的声明 并且(自 C++26 起) 在块作用域 S 中绑定名称,该块作用域 S

  • lambda 表达式的 复合语句 { body }
(自 C++11 起)
  • 选择或迭代语句的子语句,该子语句本身不是选择或迭代语句,或
  • 函数 try 块的处理程序

可能与其目标作用域为 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

  • 如果声明的参数是 函数声明 的参数列表的参数,
  • 如果函数声明是 函数定义,则引入的作用域扩展到函数定义的末尾。
  • 否则(函数声明是函数原型),则引入的作用域扩展到函数声明符的末尾。
  • 在这两种情况下,作用域都不包含函数声明的 位置
  • 如果声明的参数是 lambda 表达式 的参数列表的参数,则引入的作用域扩展到 { body } 的末尾。
(自 C++11 起)
  • 如果声明的参数是 推导指南 的参数列表的参数,则引入的作用域扩展到该推导指南的末尾。
(自 C++17 起)
  • 如果声明的参数是 requires 表达式 的参数列表的参数,则引入的作用域扩展到 { requirement-seq } 的末尾。
(自 C++20 起)
int f(int n) // the declaration of the parameter “n”
{            // introduces a function parameter scope
    /* ... */
}            // the function parameter scope ends here

Lambda 作用域

每个 lambda 表达式 引入一个lambda 作用域,该作用域从 [captures ] 之后立即开始,并扩展到 { body } 的末尾。

lambda 表达式 E 的带初始化器的 捕获 位于 E 引入的 lambda 作用域中。

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命名空间定义 引入一个命名空间作用域 S,该作用域包含 N 的每个命名空间定义的 声明

对于每个非友元重新声明或特化,其目标作用域为 S 或包含在 S 中,以下部分也包含在作用域 S

  • 对于 (模板)重新声明或类模板特化,其后的部分为 class-head-name
  • 对于 枚举 重新声明,其后的部分为 enum-head-name
  • 对于任何其他重新声明或特化,其后的部分为 声明符unqualified-idqualified-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 的声明引入一个类作用域 S,该作用域包含 C类定义member-specification

对于每个非友元重新声明或特化,其目标作用域为 S 或包含在 S 中,以下部分也包含在作用域 S

  • 对于 (模板)重新声明或类模板特化,其后的部分为 class-head-name
  • 对于 枚举 重新声明,其后的部分为 enum-head-name
  • 对于任何其他重新声明或特化,其后的部分为 声明符unqualified-idqualified-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 起) 枚举声明enumerator-list(如果存在)。

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 引入一个模板参数作用域 S,该作用域从 D 的模板参数列表的开头扩展到 D 的末尾。任何位于模板参数列表之外的声明,如果本来应该位于 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

[编辑] 声明点

通常,名称在其第一个声明的位置之后可见,该位置如下确定。

简单声明中声明的名称的位置位于该名称的 声明符 之后,位于其初始化器之前(如果有)。

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
}

类或类模板声明的位置位于其 类头部 中命名该类的标识符(或命名该模板特化的 template-id)之后。类或类模板名称已经在基类列表的作用域中。

struct S: std::enable_shared_from_this<S> {}; // S is in scope at the colon

枚举说明符 或不透明枚举声明(自 C++11 起) 的位置位于命名该枚举的标识符之后。

enum E : int // E is in scope at the colon
{
    A = sizeof(E)
};

类型别名或别名模板 声明的位置位于别名引用的 type-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 起)


结构化绑定声明 的位置位于 identifier-list 之后,但结构化绑定初始化器禁止引用任何正在声明的名称。

(自 C++17 起)


范围-for 循环range-declaration 中声明的变量 或结构化绑定(自 C++17 起) 的位置位于 range-expression 之后。

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++20 起)

命名 命名空间定义 的位置位于命名空间名称之后。

[编辑] 缺陷报告

以下行为变更缺陷报告被追溯应用于先前发布的 C++ 标准。

DR 应用于 已发布的行为 正确行为
CWG 2793 C++98 块作用域中的 extern 声明可能
与父作用域中的另一个声明冲突
禁止

[编辑] 参考文献

  • C++23 标准 (ISO/IEC 14882:2024)
  • 6.4 作用域 [basic.scope]
  • C++20 标准 (ISO/IEC 14882:2020)
  • 6.4 作用域 [basic.scope]
  • C++17 标准 (ISO/IEC 14882:2017)
  • 6.3 作用域 [basic.scope]
  • C++14 标准 (ISO/IEC 14882:2014)
  • 3.3 作用域 [basic.scope]
  • C++11 标准 (ISO/IEC 14882:2011)
  • 3.3 作用域 [basic.scope]
  • C++98 标准 (ISO/IEC 14882:1998)
  • 3.3 声明区域和作用域 [basic.scope]

[编辑] 另请参阅

C 文档作用域