问题 使用具有相同名称的类和枚举?


我有一个类和一个具有相同名称的枚举值。在课堂内我想使用枚举,它会产生错误。有没有办法使用枚举  重命名或移动到不同的命名空间?

例:

namespace foo {
    enum bar {
        BAD
    };

    class BAD {
        void worse () {
            bar b = BAD; // error
        }
    };
};

3981
2018-02-12 09:49


起源

哦,拜托......你不能把枚举放进去 struct 它本身是为了避免冲突,至少呢? - Matthieu M.
为了提高可读性,我强烈建议您选择不同的名称 enum 和 class。请记住,更好的目标是生成易于维护的软件,而不是在编译器或语言中调用细微之处。 - Thomas Matthews


答案:


这是如何执行名称查找的棘手部分之一。

C ++中有两个标识符范围,一个用于类类型和一般标识符范围。枚举值BAD驻留在通用标识符范围中,而类类型BAR驻留在类标识符范围中。这就是为什么允许你同时拥有枚举值和具有相同名称的类的原因:两个名称都不会发生冲突。

在BAD类中,标识符查找规则将在找到枚举之前找到类BAD,从而找到错误。现在,如果您完全限定标识符,则名称查找将首先检查全局标识符范围并匹配枚举值。在另一端,你将不得不添加 struct 要么 class 用于声明BAD类型的变量的关键字。

namespace foo {
   enum bad { BAD; };
   class BAD {
      void worse() { bad b = ::foo::BAD; } // fully qualified will match the enum
   };
}
int main() {
   // foo::BAD b;    // error, foo::BAD is an enum, not a type
   class foo::BAD b; // correct
}

现在,我会反对这种用法。重复使用这样的标识符通常不是一个好主意。代码将更复杂,并且可能会对随意读者产生误导(相同的非限定标识符在不同的上下文中使用时指的是不同的东西)。如果名称确实需要 BAD,考虑为类或枚举使用封闭的命名空间或类(更喜欢那里的枚举)。


9
2018-02-12 10:09





 bar b = foo::BAD;

或者如果您在全局命名空间中

 bar b = ::BAD;

但是这个名称重载不是我推荐的。 C ++ 0X将允许

 bar b = bar::BAD;

如果对C ++ 0X的依赖是可接受的,这是一个更好的解决方案。

正如所承诺的,解释

9.1 / 2

如果在声明了同名对象,函数或枚举器的作用域中声明了类名,则两个声明都在作用域中,该类只能使用 详尽型说明符 (3.4.4)

详尽型说明符 是形式

class BAD b;

这是为了与C兼容,其中标签名称在不同的名称空间中,如果想要在没有精心设计的类型说明符的情况下使用它们,则必须是[i] typedef [/ i] ed。 (一个众所周知的函数示例是Unix中的struct stat和function stat)。

这解释了为什么重载名称以指定类和枚举器是可能的。 BAD在这里指定类的原因是类的名称也被定义到类范围中,并且在成员函数定义中,搜索范围是按顺序排列的:     - 成员函数范围     - 班级范围     - 包含类定义的命名空间

在类范围内找到BAD,因此永远不会搜索名称空间foo。


5
2018-02-12 09:53



有人想知道我是否尝试过。我做了3个不同的编译器,包括como。规则是晦涩的,如果我记得我有时间的话,我会用参考文献给出更全面的解释。 - AProgrammer
++,你是对的 - Eli Bendersky


不,没有办法做到这一点。您应该使用有效的标识符。有效的标识符意味着您必须能够 鉴定 用它。 :)


0
2018-02-12 09:51





这适用于VS2008,但会发出警告:

bar b = bar::BAD;

这不是我可以推荐的东西。

你应该把枚举放在另一个命名空间里面 foo 并且两者都有资格 bar 和 BAD 使用新的命名空间。


0
2018-02-12 10:00



这是C ++ 0X语法,如果可用的话,它是首选的解决方案。我的解决方案是C ++ 03语法(但使用神秘的规则)。 - AProgrammer