【问题标题】:Why doesn't clang allow accessing a nested enum class through an instance?为什么 clang 不允许通过实例访问嵌套的枚举类?
【发布时间】:2018-04-25 17:16:34
【问题描述】:

考虑以下代码:

struct S {
    enum class EnumClass {
        one
    } ;

    enum Enum {
        one
    };
};

int main()
{
    S s;
    S::EnumClass e = s.EnumClass::one; // <- Doesn't compile with clang
    S::Enum e11 = s.Enum::one;
    S::Enum e12 = s.one;
}

一切都适用于 GCC,但 clang(3.8 和 3.9 都不是)无法编译 s.EnumClass::one,出现错误:'S::EnumClass::one' is not a member of class 'S'

鉴于无作用域枚举工作正常,这似乎是一个错误。

【问题讨论】:

  • 有趣... Visual Studio 将愉快地编译它而不会发出警告,但智能感知会突出显示与 Clang 相同的错误。巧合?
  • @Rakete1111 但也许枚举值可以被视为封闭类的成员(某种静态?)。
  • @HolyBlackCat 参见 [class.member]p1 和 p3。他们被认为是班级的成员,听起来很奇怪。
  • 那么应该如何访问嵌套的(枚举)类成员呢?

标签: c++ clang language-lawyer


【解决方案1】:

这是 gcc1 中的一个错误。相关措辞在[expr.ref]p2

在任何一种情况下,id-expression [这里:EnumClass::one] 都应命名该类或其基类之一的成员。

EnumClass::one 不是指类的成员,它是枚举的成员。该枚举是否属于该类并不重要,只是成员one 本身不是该类的一部分。

但是Enum::one 是班级的一部分吗?是的,根据[class.member]p1

类的成员是数据成员、成员函数、嵌套类型、枚举器以及成员模板及其特化。

并在[class.member]p3 中更明确:

类中定义的无作用域枚举的枚举数是该类的成员。


1:我什至会称其为标准中的错误,因为似乎没有任何(技术)原因应该禁止这样做,我认为允许它是个好主意。不过有关于允许它的讨论,所以让我们看看委员会的决定。

【讨论】:

  • 关于什么是成员和不是成员,它似乎与被 gcc、clang、Intel 和 MSVC 等拒绝的struct S { struct T { static const int t = 0; }; } s; int main() { return s.T::t; } 相同。如果这不被接受,我不明白为什么 enum 等效项应该有任何不同,所以我很难将其视为标准中的错误,而不仅仅是 gcc(和 MSVC)中的错误。
  • @hvd 我的意思是这也应该改变,因为它没有任何意义 IMO。 :)
  • 语法s.T::t 已经有了明确的含义,即从基类访问成员,即使它们可能已被派生类隐藏。我想可以例外,. 的 LHS 表达式不需要从声明类型派生,如果它实际上不会被使用,但这也会允许很多不受欢迎的东西,并破坏现有的代码依赖于 SFINAE。
  • expr.ref#4.4 还表示表达式 E1.E2 格式错误,除非 (expr.ref#4.4) E2 是成员枚举数。 dcl.enum#11 表示作用域枚举器具有其枚举的作用域,只有在类作用域中声明的枚举器(即非作用域枚举)才能使用类成员访问运算符引用。
  • @Rakete1111:+1 如果您愿意解释一下应该如何访问嵌套(枚举)类成员,那么?
猜你喜欢
  • 1970-01-01
  • 2012-10-01
  • 2018-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多