为什么不能在C++中重新定义类中的类型名称?

zhe*_*oli 4 c++ scope class typename

根据C++ Primer一节,7.4.1类型名称是特殊的:

通常,内部作用域可以从外部作用域重新定义名称,即使该名称已在内部作用域中使用过.但是,在类中,如果成员使用外部作用域中的名称并且该名称是类型,则该类可能不会随后重新定义该名称.

因此,例如:

typedef double Money;
class Account {
    public:
        Money balance() { return bal; }
    private:
        typedef double Money;
        Money bal;
};

int main() {
    typedef double Money;
    Money asset;
    typedef double Money;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当你编译上面的例子时,它会抱怨:

a.cc:6:24: error: declaration of ‘typedef double Account::Money’ [-fpermissive]
         typedef double Money;
                        ^
a.cc:1:16: error: changes meaning of ‘Money’ from ‘typedef double Money’ [-fpermissive]
 typedef double Money;
Run Code Online (Sandbox Code Playgroud)

那么为什么我们不能在类中重新定义类型名称,但我们可以在内部范围内吗?


我的编译器版本是g++ (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609.
该部分还有一个注释:

虽然重新定义类型名称是错误的,但编译器不需要诊断此错误.即使程序出错,一些编译器也会悄悄地接受这样的代码.

T.C*_*.C. 10

这不是类型所特有的.[basic.class.scope]/2:

N类中使用的名称S应在其上下文中引用相同的声明,并在完成的范围内重新评估S.违反此规则无需诊断.

原因是类范围中的名称查找有点特殊.考虑:

using Foo = int;

struct X {
    Foo a;    // ::Foo, i.e., int
    void meow() { 
        Foo b = a; // X::Foo; error: no conversion from int to char*
    }
    using Foo = char*;
};
Run Code Online (Sandbox Code Playgroud)

成员函数体中的名称查找会考虑所有类成员,无论是在成员函数之前还是之后声明(否则,在类定义中定义的成员函数将无法使用稍后在类中声明的数据成员).结果是你得到两个Foo具有不同含义的s,即使它们都是词法上在类成员Foo的声明之前.这很容易导致极其混乱和脆弱的代码,因此标准禁止它.