简体   繁体   English

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

[英]repeated extern declarations of qualified identifiers C++

Why is it that qualified names cannot be re-declared inside functions? 为什么合格的名称不能在函数内重新声明?

The following code fails to compile (in MSVC2015 and clang) 以下代码无法编译(在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;
}

However, if we move the two lines extern int N::j; 但是,如果我们移动两行extern int N::j; to just before void foo() then the code compiles fine. 就在void foo()之前,代码编译得很好。


UPDATE It is noteworthy that 更新值得注意的是

  1. repeated declarations of unqualified names do work, 重复声明不合格的名字确实有效,
  2. both ::i and ::N::j were already defined in their respective declarations, ::i::N::j都已在各自的声明中定义,
  3. ::N::j is not visible to foo ::N::jfoo不可见
  4. the grammar does allow extern int ::N::j and it is not a definition 语法允许extern int ::N::j并且它不是定义
  5. the following code also fails (thank to TC for pointing this out) 以下代码也失败了(感谢TC指出这一点)

.

int i;
void foo()
{
    extern int ::i;
}
  1. the following code works in MSVC but it gives a warning in clang 以下代码在MSVC中有效,但它在clang中发出警告

.

int i;
extern int ::i;

TC directed me to [dcl.meaning]p1 TC指导我[dcl.meaning] p1

… When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers (or, in the case of a namespace, of an element of the inline namespace set of that namespace (7.3.1)) or to a specialization thereof … ...当declarator-id被限定时,声明应引用先前声明的限定符所引用的类或命名空间的成员(或者,如果是命名空间,则引用该命名空间的内联命名空间集的元素) 7.3.1))或其专业化......

It seems to me that this is a case where the standard is not faithfully represented by the implementations. 在我看来,这是一个案例,其中标准没有忠实地表示实现。

It is the namespace member definition vs. declaration issue here. 这是命名空间成员定义与声明问题。 Please see C++11 spec: 请参阅C ++ 11规范:

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

1 Members (including explicit specializations of templates (14.7.3)) of a namespace can be defined within that namespace. 1可以在该命名空间中定义命名空间的成员(包括模板的显式特化(14.7.3))。 [ Example: namespace X { void f() { / ... / } } —end example ] [示例:名称空间X {void f(){/ ... /}} - 示例]

2 Members of a named namespace can also be defined outside that namespace by explicit qualification (3.4.3.2) of the name being defined, provided that the entity being defined was already declared in the namespace and the definition appears after the point of declaration in a namespace that encloses the declaration's namespace. 2通过定义名称的显式限定(3.4.3.2),也可以在该命名空间外定义命名命名空间的成员,前提是已定义的实体已在命名空间中声明,并且定义出现在声明中的声明之后包含声明命名空间的命名空间。

Therefore, the revised code below compiles. 因此,下面的修订代码编译。

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;
}

Here is a generic example of using extern with namespace : In one CPP file: 以下是使用extern with namespace的一般示例:在一个CPP文件中:

namespace N
{
    int j;
}

In its header file: 在其头文件中:

namespace N
{
    extern int j;
}

Update: 更新:

More on extern, namespace, declaration and definition 有关extern,命名空间,声明和定义的更多信息

The :: scope resolution operator cannot be use for declaration. :: scope resolution运算符不能用于声明。 It may be used for definition. 它可以用于定义。 Using :: for extern declaration would be ill-formed. 使用:: for extern声明将是不正确的。 Please see C++11 spec: 请参阅C ++ 11规范:

7.5 Linkage specifications [dcl.link] ... ... 7.5链接规范[dcl.link] ......
4 Linkage specifications nest. 4连杆规格嵌套。 When linkage specifications nest, the innermost one determines the language linkage. 当链接规范嵌套时,最里面的规则确定语言链接。 A linkage specification does not establish a scope. 链接规范不会建立范围。 A linkage-specification shall occur only in namespace scope (3.3). 链接规范只应在命名空间范围内发生(3.3)。 In a linkage-specification, the specified language linkage applies to the function types of all function declarators, function names with external linkage, and variable names with external linkage declared within the linkage-specification. 在链接规范中,指定的语言链接适用于所有函数声明符的函数类型,具有外部链接的函数名称,以及在链接规范中声明的具有外部链接的变量名称。

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

1 The declarative region of a namespace-definition is its namespace-body. 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM