简体   繁体   English

重新定义类型名称是否合法?

[英]Is it legal to redefine a type name?

Chapter 7.4.1 of the book C++ Primer says the following: C++ Primer 一书的第 7.4.1 章说:

Ordinarily, an inner scope can redefine a name from an outer scope even if that name has already been used in the inner scope.通常,内部 scope 可以从外部 scope 重新定义名称,即使该名称已在内部 scope 中使用。 However, in a class, if a member uses a name from an outer scope and that name is a type, then the class may not subsequently redefine that name但是,在 class 中,如果成员使用来自外部 scope 的名称并且该名称是类型,则 class 随后可能不会重新定义该名称

The word subsequently makes me think that it is only an error to redefine a type name after it has been used in the class.这个词随后让我认为在 class 中使用类型名称后重新定义它只是一个错误。 However, two paragraphs later it says:然而,两段后它说:

Although it is an error to redefine a type name, compilers are not required to diagnose this error.尽管重新定义类型名称是错误的,但编译器不需要诊断此错误。

Does this mean that it is an error to redefine a type name even before it has been used in a class?这是否意味着在 class 中使用类型名称之前重新定义它是错误的?

It seems that the quote refers to the following case似乎引用是指以下情况

typedef int T;

struct A
{
    T a[10];
    typedef double T;
};

That is the code is ill-formed due to the redeclaration of the name T within the class definition that was already used in the declaration of the data member a .也就是说,由于在数据成员a的声明中已使用的 class 定义中重新声明了名称T ,因此代码格式错误。

If you will just write如果你只写

typedef int T;

struct A
{
    int a[10];
    typedef double T;
};

then this code is correct.那么这段代码是正确的。 The name T is not used as a type specifier in declarations of members of the class A.在 class A 的成员声明中,名称T不用作类型说明符。

The OP writes in the comment section: OP在评论部分写道:

... My question is wether [ sic ] it is legal to redefine a type name before it has been used in a class. ...我的问题是 [原文如此] 在 class 中使用之前重新定义类型名称是否合法。

The answer is yes.答案是肯定的。 It is legal to define a type name in a class that shadows a type name in an enclosing scope.在 class 中定义类型名称是合法的,它会在封闭的 scope 中隐藏类型名称。 What is not allowed is the following:不允许的情况如下:

  • A name, call it T (though it need not be a type), is used inside a class, and name lookup finds some declaration D , and在 class 中使用名称,称为T (尽管它不必是类型),名称查找会找到一些声明D ,并且
  • The class declares a member named T , and class 声明了一个名为T的成员,并且
  • After the class has been completely defined, if the compiler goes back and parses the previous use of the name T , it now finds the new member declaration instead of D .在完全定义 class 之后,如果编译器返回并解析之前使用的名称T ,它现在会找到新的成员声明而不是D

Let's go over a few examples to clarify the issue.让我们通过几个例子来说明问题。

using T = X;
class C {
    using T = Y;
    T x;
};

The above example is legal because when the compiler sees T x;上面的例子是合法的,因为当编译器看到T x; , it has already seen using T = Y; , 它已经using T = Y; , so T can only resolve to Y . ,所以T只能解析为Y There are no subsequent declarations inside the class that can change the meaning later. class 内部没有后续可以更改含义的声明。

using T = X;
class C {
    T x;
    using T = Y;
};

The above example is illegal.上面的例子是非法的。 The compiler at first looks up T and finds the enclosing definition of T as X , since C::T hasn't been declared yet.编译器首先查找T并找到T的封闭定义为X ,因为C::T尚未声明。 But after C::T has been declared, it implies that if T x;但是在声明了C::T之后,意味着如果T x; were to be reinterpreted, then T would now refer to C::T instead, since the class scope takes precedence over the enclosing scope. were to be reinterpreted, then T would now refer to C::T instead, since the class scope takes precedence over the enclosing scope.

using T = ::X;
class C {
    T x;
    using T = ::X;
};

The above example is illegal.上面的例子是非法的。 The fact that both declarations of T make it refer to the same type is not relevant. T的两个声明都使其引用相同类型的事实无关紧要。 The violation occurs because T x;违规发生是因为T x; would find a different declaration of T after the class is completely defined.在完全定义 class 之后会发现T不同声明

using T = X;
class C {
    ::T x;
    using T = Y;
};

The above example is legal.上面的例子是合法的。 The declaration using T = Y; using T = Y; does not change the meaning of ::T , because ::T will always refer to the global declaration even though C::T is there.不会改变::T的含义,因为::T将始终引用全局声明,即使C::T存在。

using T = X;
class C {
    void foo() { T x; }
    using T = Y;
};

The above example is legal.上面的例子是合法的。 The body of foo is a complete-class context , which implies that name lookup for T is not done until after the entire class has been seen. foo的主体是一个完整的类 context ,这意味着直到看到整个 class 之后才完成对T的名称查找。 Put another way, the declaration using T = Y;换句话说,声明using T = Y; in a sense always "precedes" the body of foo so this is similar to the first example.在某种意义上总是“先于” foo的主体,所以这类似于第一个示例。

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

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