重复的限定标识符C ++的extern声明

时间:2015-07-30 17:07:15

标签: c++ c++11 language-lawyer

为什么不能在函数内重新声明限定名?

以下代码无法编译(在MSVC2015和clang中)

int i;

namespace N
{
int j;
}

void foo()
{
    extern int i;
    extern int i;
    extern int N::j;
    extern int N::j;
}

int main()
{
    return 0;
}

但是,如果我们将两行extern int N::j;移到void foo()之前,那么代码编译就可以了。

更新值得注意的是

  1. 不合格名称的重复声明确实有效,
  2. ::i::N::j已在各自的声明中定义,
  3. {li> ::N::jfoo 不可见
  4. 语法允许extern int ::N::j不是定义
  5. 以下代码也失败了(感谢T.C.指出这一点)
  6. int i;
    void foo()
    {
        extern int ::i;
    }
    
    1. 以下代码适用于MSVC,但它在clang中发出警告
    2. int i;
      extern int ::i;
      

2 个答案:

答案 0 :(得分:2)

T.C。指示我[dcl.meaning] p1

  

...当declarator-id被限定时,声明应引用先前声明的限定符所引用的类或命名空间的成员(或者,如果是命名空间,则引用内联命名空间集的元素)该命名空间(7.3.1))或其专业化......

在我看来,这是一个标准没有被实施忠实代表的情况。

答案 1 :(得分:1)

这里是命名空间成员定义与声明问题。请参阅C ++ 11规范:

  

7.3.1.2命名空间成员定义[namespace.memdef]

     

1个成员(包括模板的明确专业化(14.7.3))   命名空间可以在该命名空间中定义。   [示例:名称空间X.   {void f(){/ ... /}} -end example]

     

2名成员   命名空间也可以通过显式在该命名空间外定义   定义名称的资格(3.4.3.2),前提是   正在定义的实体已经在命名空间中声明了   定义出现在命名空间中的声明点之后   包含声明的命名空间。

因此,下面修改后的代码编译。

int i;

namespace N
{
    int j;

    void foo()
    {
        extern int i;
        extern int j;
    }
}

void foo()
{
    extern int i;

    using namespace N;
    extern int j;
}

int main()
{
    return 0;
}

以下是externnamespace一起使用的一般示例: 在一个CPP文件中:

namespace N
{
    int j;
}

在其标题文件中:

namespace N
{
    extern int j;
}

更新:

有关extern,名称空间,声明和定义的更多信息

:: scope resolution运算符不能用于声明。它可以用于定义。使用:: for extern声明将是不正确的。 请参阅C ++ 11规范:

  

7.5链接规范[dcl.link]   ...... ...   4连杆规格嵌套。当连接规格嵌套时,最里面   一个决定了语言的联系。 链接规范没有   建立范围。链接规范只能在   命名空间范围(3.3)。在链接规范中,指定的   语言链接适用于所有函数的函数类型   声明符,具有外部链接的函数名称和变量名称   在链接规范中声明了外部链接。

     

3.3.6命名空间范围[basic.scope.namespace]

     

1命名空间定义的声明性区域是其namespace-body。 ...

// Compiled with VC2013.
// extern int ::i;   // error C2039: 'i' : is not a member of '`global namespace''
extern int i;     // declaration  
int i;  // definition

namespace N
{
    extern int j;  // declaration
}
int N::j;  // definition
namespace N
{
     // int j;  // definition
}

void foo()
{
    // extern int ::i;  // fatal error C1506: unrecoverable block scoping error
    extern int i;     // declaration  
    // extern int N::j;  // error C2086: 'int N::j' : redefinition
}

int main()
{
    return 0;
}
相关问题