范围单词组合中使用的名称的含义

时间:2014-06-18 19:08:53

标签: c++ class language-lawyer

我不明白name used in...的感觉。这是什么意思?例如(3.4.1 / 7):

  

在成员之外定义类X的名称   功能体......

考虑以下示例:

class A { static const int a = 4; }

int b = A::a;

在用于全局范围的嵌套名称说明符之后的名称a还是用于类范围?

命名空间模拟在7.3.1 / 6中非常清楚地定义:

  

声明的封闭命名空间是其中的命名空间   声明词汇出现,除了重新声明   在其原始命名空间之外的命名空间成员(例如,定义   如7.3.1.2)中所述。

2 个答案:

答案 0 :(得分:1)

免责声明:警告,语言答案。

什么是"范围"?

通常,我会说范围被理解为{}所包含的程序文本中除初始化括号之外的部分。 TC ++ PLv4 p157"声明将一个名称引入范围"。

声明区域

在[basic.scope.declarative] / 1中,我们找到声明区域的定义

  

程序文本的某些部分引入了每个名称,称为声明区域,这是该名称​​有效的程序的最大部分,即其中该名称可用作非限定名称以引用同一实体。

我认为我们可以看到"之后的部分"作为名称有效性的定义

范围

[basic.scope.declarative] / 1继续定义范围

  

通常,每个特定名称仅在某些可能不连续的情况下有效   程序文本的一部分称为范围

这只定义名称的范围。在全球范围内使用的短语""或者"在类"范围内使用,术语范围与特定名称无关。同样,[basic.scope.declarative] / 3

  

声明声明的名称被引入声明发生的范围,[...]除外。

此处,术语范围也用于第二种含义,与特定名称无关。

定义"范围"

的第二个含义

一些语言功能(如块语句,命名空间和类)引入了新的范围。例如。 [stmt.block] / 1

  

复合语句定义块范围。

第二种含义中的

范围至少在三种不同的情境中使用:

  • 在X
  • 的范围内查找
  • 用于X
  • 的范围
  • 属于X
  • 的范围

在X

的范围内查找

示例:3.4.3 / 1

  

如果 qualified-id 嵌套名称说明符指定了一个类,则在 nested-name-specifier 之后指定的名称除了下面列出的情况外,我们会在课程范围内查找。

class X
{
    int m;
    void foo() { int n; }
};

decltype(X::m) v; // legal
decltype(X::n) w; // illegal

在此上下文中,类X范围不会扩展到任何嵌套范围,例如成员函数或嵌套类。

在X

的范围内使用

示例:3.3.7 / 2

  

类成员的名称只能按如下方式使用:

     
      
  • 在其类的范围内(如上所述)或从其类派生的类
  •   
  • [...]
  •   
class X
{
    int m;
    void foo()
    {
        decltype(m) n;
    }
    static int o;
};
int X::o = decltype(m)();

此处,类X 范围扩展到嵌套范围和程序的其他部分,例如类主体外部成员的定义。

请注意,静态数据成员,嵌套类和本地类的初始化程序在范围内显式定义为,只要声明了静态数据成员/类。对于成员函数,我只能找到非规范性的注释,例如9.3 / 5

  

f的成员函数X在全局范围内定义;表示法X::f指定函数f是类X的成员,并且在类X的范围内。

据我所知,这个"属于"对于成员函数和嵌套/本地类,表示那些新引入的作用域是嵌套作用域。

"用于X"在标准中不经常发生。有人可能会争辩说3.3.7 / 2应该扩展到嵌套范围,以便在"范围内使用。符合"在#34;。

的范围内查找

属于X

的范围

示例:8.5 / 13

  

静态成员的初始化程序属于成员类的范围。

class X
{
    static int m;
    static int n;
};

int n;
int o;

int X::m = n; // X::n
int X::n = o; // ::o

非限定名称的名称查找按照每个相应类别中列出的顺序搜索范围(复数)"" [basic.lookup.unqual] / 1。对于两个静态数据成员的初始值设定项,首先搜索类X的范围,然后搜索任何基类,然后搜索封闭范围(此处:全局范围),[basic.lookup.unqual] / 7。

&{34>的含义是X"在我看来,对于不合格的查找,搜索的范围是搜索X 中使用的名称的范围,可能还有访问规则(静态数据成员的初始化程序可以访问私有成员等) 。如上所述,这有效地嵌套了成员函数的范围和在其封闭类之外定义的嵌套类。在那个封闭类的范围内的身体。

尝试定义X

的范围

不包括"在#"范围内使用的奇怪扩展名。

3.3.3至3.3.9对各种名称范围进行分类。我们可以使用这些类别对可以声明名称的程序部分进行分类:程序的一部分,其中可以声明具有块作用域的名称​​是块作用域。程序的一部分,其中可以声明具有类范围的名称​​是类范围。我们仍然需要区分同类的不同范围:

void foo()
{                   // begin scope A
    int a;          // 
    {               // begin scope B
        int b;      // 
        int c;      //
    }               // end scope B
    int d;          //
}                   // end scope A

标准调用A外部范围B(在名称查找中)。但是,范围B不是范围A的一部分。也许" B之类的内容属于A,但B内声明的名称不在A"范围内。考虑:

class A
{
    int m;
    class B
    {
        int n;
    };
};

这里,名称查找"在班级A"的范围内无法通过不合格的查找找到嵌套类B的成员。同样相关:匿名工会。

我认为执行此分离的最佳方法是查看可引入范围的各个语言功能。例如,[stmt.block] / 1"复合语句定义块范围。"然后我们可以查看程序的任何部分X,找到引入尚未结束的范围的最接近的先前语言特性(*),获取程序的所有区域,其中新声明的名称在同一范围内(**) ),并将其称为X 封闭范围。

(*)尚未结束:表示块,块结束等(即,由语言功能指定)或者,尚未结束 =可能已声明的名称仍然有效
(**)在同一范围内:搜索,从这个新声明开始,引入尚未结束的范围的最接近的先前语言特征,应该找到程序的相同部分

这似乎符合[basic.scope.declarative] / 4中使用的声明区域的定义:

  

给定一个声明区域中的一组声明,每个声明都指定相同的非限定名称,它们都应引用同一个实体,或[... =函数重载],或[... =各种例外]。

据我所知,这与[basic.scope.declarative] / 1中的定义相矛盾:

int main()
{
    int x;
    {
        int x;
    }
}

这里,我们有两个声明指定相同的非限定名称。外部x作为名称在内部{}内也有效;然而,这是一个完全合法的C ++程序。我怀疑声明区域实际上不应该与单个名称相关联。

我认为可以使用终端{}简化范围的定义。

答案 1 :(得分:0)

这句话

  

在成员之外定义类X的名称   功能体......

考虑在类的定义中使用的所有名称,这些名称从类头开始并在结束括号中结束,不包括成员函数中使用的名称(成员函数中使用的名称在其他段落中考虑)。

例如

class B : public A
{
   int x;
   int a[i];
   C z;
   //..
};

所以这些名字是A,x,a,i,C,z。

考虑到虽然在类中定义了名称x,a和z,但是它们的名称可以在类的其他成员定义中使用。

至于您的代码示例

class A { static const int a = 4; }

int b = A::a;

The name a after the nested-name-specifier used into the global scope or it used into the class scope?

然后在类A的类范围中搜索名称a,但在全局范围中使用它的限定名来初始化变量b。

考虑另一个例子,虽然它与您引用的短语没有任何共同之处但与您的代码有关系。

struct A
{
    static int a;
    static int b;
};

int A::a = 10;
int A::b = a;

这里使用名称a而没有嵌套的名称说明符。如何在类范围内搜索名称是另一个规则。