简体   繁体   English

当我使用已在类外声明并稍后在类内声明的名称时,这是未定义的行为还是非法行为?

[英]Is it undefined behavior or illegal, when I use a name that is both already declared outside of the class and later declared inside the class?

What happens when:在以下情况下会发生什么:

  1. I declare and define a name X (either object or type) in the global scope.我在全局范围内声明并定义了一个名称 X(对象或类型)。
  2. I start writing a class.我开始写一门课。 Inside the class, but outside of function bodies etc., I use X.在类内部,但在函数体等之外,我使用 X。
  3. Later in the class, I declare name X again.稍后在课堂上,我再次声明名称 X。

On the Class Scope page on cppreference.com , this is considered undefined behavior .cppreference.com 的 Class Scope 页面上,这被视为未定义行为 The code snippet looks like this:代码片段如下所示:

typedef int c; // ::c
enum { i = 1 }; // ::i
class X {
    char v[i]; // Error: at this point, i refers to ::i
               // but there is also X::i
    int f() {
         return sizeof(c); // OK: X::c, not ::c is in scope inside a member function
    }
    char c; // X::c
    enum { i = 2 }; // X::i
};
 
typedef char* T;
struct Y {
    T a; // Error: at this point, T refers to ::T
         // but there is also Y::T
    typedef long T;
    T b;
};

But in Chapter 3.1 of Stanley B. Lippman's book Inside the C++ Object Model , the compiler should raise an error .但是在 Stanley B. Lippman 的书Inside the C++ Object Model 的第 3.1 章中,编译器应该引发错误

His comments:他的评论:

In the following code fragment, for example, the type of length in both member function signatures resolves to that of the global typedef—that is, to int .例如,在以下代码片段中,两个成员函数签名中的 length 类型都解析为全局 typedef 的类型,即int When the subsequent declaration of the nested typedef of length is encountered, the Standard requires that the earlier bindings be flagged as illegal当遇到长度的嵌套 typedef 的后续声明时,标准要求将较早的绑定标记为非法

His code snippet looks like this:他的代码片段如下所示:

typedef int length;
class Point3d {
public:
  // oops: length resolves to global
  // ok: _val resolves to Point3d::_val
  void mumble( length val ) { _val = val; }
  length mumble() { return _val; }

private:
  // length must be seen before its first reference within the class.
  // This declaration makes the prior reference illegal.
  typedef float length;
  length _val;
};

I tested with clang 7.0.0, there is no warning or error, and the length seems to bind to int .我用 clang 7.0.0 测试过,没有警告或错误, length似乎绑定到int I understand that compiler testing results cannot be used to analyze UBs, so I'm asking this question.我知道编译器测试结果不能用于分析 UB,所以我问这个问题。

Who is right?谁是对的? Or if they are both right, what am I missing?或者如果他们都是对的,我错过了什么? What does the current standard say about this?目前的标准对此有何看法?

The question already points to the proper cppreference snippet [Class Scope] :问题已经指向正确的 cppreference 片段[Class Scope]

The potential scope of a name declared in a class begins at the point of declaration and includes the rest of the class body and all function bodies ...在类中声明的名称的潜在范围从声明点开始,包括类主体的其余部分和所有函数主体......

Then on the same cppreference page:然后在同一个 cppreference 页面上:

If a name is used in a class body before it is declared, and another declaration for that name is in scope, the program is ill-formed, no diagnostic required.如果在声明之前在类体中使用了一个名称,并且该名称的另一个声明在范围内,则程序格式错误,不需要诊断。

According to the above it sounds like gcc is right with the error and clang is also right (as no diagnostic is required) but is being too permissive allowing ill formed code to compile.根据上面的说法,听起来gcc对错误是正确的, clang也是正确的(因为不需要诊断),但过于宽容,允许编译格式错误的代码。

The relevant wording in the spec [basic.scope.pdecl] 6.4.2/1 - Point of Declaration :规范[basic.scope.pdecl] 6.4.2/1 - Point of Declaration 中的相关措辞:

... The point of declaration for an enumeration is immediately after the identifier (if any) in either its enum-specifier ([dcl.enum]) or its first opaque-enum-declaration ([dcl.enum]), whichever comes first. ... 枚举的声明点紧跟在其枚举说明符 ([dcl.enum]) 或其第一个 opaque-enum-declaration ([dcl.enum]) 中的标识符(如果有)之后,以出现者为准第一的。 The point of declaration of an alias or alias template immediately follows the defining-type-id to which the alias refers.别名或别名模板的声明点紧跟在别名所引用的定义类型 ID 之后。

And [basic.scope.declarative] 6.4.1/4.2 :[basic.scope.declarative] 6.4.1/4.2

exactly one declaration shall declare a class name or enumeration name that is not a typedef name and the other declarations shall all refer to the same variable, non-static data member, or enumerator, or all refer to functions and function templates;只有一个声明应声明一个不是 typedef 名称的类名或枚举名,而其他声明应全部引用相同的变量、非静态数据成员或枚举数,或全部引用函数和函数模板; in this case the class name or enumeration name is hidden ([basic.scope.hiding]).在这种情况下,类名或枚举名是隐藏的([basic.scope.hiding])。

Then [basic.scope.class] 6.4.7/2 - Class scope :然后[basic.scope.class] 6.4.7/2 - 类范围

A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.在类 S 中使用的名称 N 应在其上下文中以及在 S 的完整范围内重新评估时引用相同的声明。违反此规则不需要诊断。

Bottom line: this code is ill formed (and thus if compiled can be viewed as undefined behavior ), however the compiler can ignore it as no diagnostic is required.底线:此代码格式错误(因此如果编译可被视为未定义行为),但是编译器可以忽略它,因为不需要诊断。

They're both right.他们都是对的。

As the article you referenced states, this does not have undefined behaviour, but is rather ill-formed, no diagnostic required .当你的文章中引用状态,这并不有不确定的操作下,而是形成不良的,没有诊断需要

This is a very specific phrase in the standard, with a very specific meaning, which correlates to exactly what you've seen: the program is ill-formed, but the implementation doesn't have to diagnose that if it doesn't want to.这是标准的一个非常具体的短语,具有非常特殊的意义,这关联到你见过什么:是形成不良的程序,但执行不具有诊断,如果它不希望.

So, you may get an error, you may not.因此,您可能会遇到错误,也可能不会。 Everything's fine.一切安好。

But fix your code.但是修复你的代码。 🙂 🙂

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

相关问题 对在类外声明的函数的未定义引用 - Undefined reference to function declared outside the class 使用在类外部声明的数据类型 - using a data type declared inside a class outside 在类或外部声明的typedef结构? - typedef structs declared inside class or outside? 当在 class 中重载运算符 &lt;&lt; 时,为什么我必须将其声明为朋友 function,尽管它已经在 class 中声明? - When overloading operator << inside a class, why I must declare it as a friend function despite the fact that it is already declared inside the class? C ++为什么我不能在声明它的类之外使用全局声明的枚举? - C++ Why am I unable to use an enum declared globally outside of the class it was declared in? 在 class 内部声明并在 class 外部定义的访问器不起作用 - Accessor declared inside the class, and defined outside the class doesn't work 当结构在 class 之外声明时,如何在 class 中返回结构? - How to Return struct in a class when gthe struct is declared outside the class? 当我声明它时,Class' 没有被声明为错误 - Class' has not been declared error when I declared it 我可以在预先声明的类中使用类型吗? - Can I use a type in a forward declared class? 如何访问另一个类中声明的类? - How do I access a class declared inside another class?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM