【问题标题】:A 'using' declaration with an enum带有枚举的“使用”声明
【发布时间】:2010-10-01 02:13:07
【问题描述】:

using 声明似乎不适用于枚举类型:

class Sample{
    public:
        enum Colour {RED, BLUE, GREEN};
}

using Sample::Colour;

不起作用!

我们是否需要为每个枚举类型的枚举器添加一个 using 声明?如下:

using sample::Colour::RED;

【问题讨论】:

  • 有没有其他方法可以做到这一点
  • 与您的问题本身并不真正相关,但我强烈建议您不要对枚举和常量使用全大写标识符。预处理器#defines 在 C/C++ 中通常是全大写的,它们会 - 处理其他同名符号。
  • 在枚举上使用作用域解析运算符 :: (如 "sample::Colour::RED") 是特定于编译器的扩展,而不是标准 C++。
  • 要了解更多关于 bk1e 对此非标准的说法,请参阅此堆栈溢出问题:Scope resolution operator on enums a compiler-specific extension?
  • @Jonathan Gawrych:链接的问题来自 09 年,那里的答案在 18 年不再适用。

标签: c++ enums using-declaration


【解决方案1】:

类没有定义命名空间,因此“using”在这里不适用。

此外,您需要公开枚举。

如果您尝试在同一个类中使用枚举,这里有一个示例:

class Sample {
 public:
  enum Colour { RED, BLUE, GREEN };

  void foo();
}

void Sample::foo() {
  Colour foo = RED;
}

并从课堂外访问它:

void bar() {
  Sample::Colour colour = Sample::RED;
}

【讨论】:

  • 一个类,除其他外,还用作命名空间。因此,任何适用于普通命名空间但不适用于类的东西都会令人惊讶。
【解决方案2】:

C++ 标准,7.3.3.1:

a 中指定的成员名称 using-declaration 在 声明区域,其中 使用声明出现。 [ 笔记: 只有指定的名称是这样 宣布;指定枚举 使用声明中的名称不 在 using-declaration 的声明式 地区。 ——尾注]

【讨论】:

  • C++ 标准还是歌剧院之夜? (对不起,无法抗拒)。
  • 你能解释一下这个成语吗,我的英语不是很好? :)
  • 我不确定标准是用英文写的。看起来很像律师说话:-)
  • 实际上,我的意思是“C++ 标准还是歌剧院之夜?”
【解决方案3】:

补充Steve Lacey's answer,原代码的问题是你引用了一个成员,但是using声明本身并不是一个成员声明:

7.3.3/6 有:

类成员的使用声明 应该是一个成员声明。

为了强调这一点,以下示例确实有效:

class Sample
{
public:
  enum Colour { RED,BLUE,GREEN};
};

class Derived : public Sample
{
public:
  using Sample::Colour;  // OK
};

最后,作为pointed out by Igor Semenov,即使将枚举定义移动到命名空间,从而允许using声明,using声明也只会声明命名空间中的枚举类型(2003 标准参考为 7.3.3/2)。

namespace Sample
{
  enum Colour { RED,BLUE,GREEN};
}

using Sample::Colour;
using Sample::BLUE;


void foo ()
{
  int j = BLUE; // OK
  int i = RED;  // ERROR
}

依赖基类型

在编译器解析类模板时允许部分和显式特化。它不会在相关基类中执行任何查找。因此,以下以 Sample 为模板的变体无法编译:

template <typename T>
class Sample
{
public:
  enum Colour { RED,BLUE,GREEN};
};

template <typename T>
class Derived : public Sample<T>
{
public:
  using Sample<T>::Colour;  // What kind of entity is Colour?

  Colour foo ()     // Not OK!
  {
  return this->RED;
  }
};

问题是Derived::Colour被编译器(14.6/2)视为对象:

在模板声明或定义中使用并且依赖于模板参数的名称被假定为不命名类型,除非适用的名称查找找到类型名称或名称由关键字 typename 限定。

查看名称为类型的两个条件:

  1. 查找 Colour 未找到类型,因为未搜索依赖基 Sample&lt;T&gt;
  2. 名称不符合typename

因此该示例需要typename 关键字:

template <typename T>
class Derived : public Sample<T>
{
public:
  using typename Sample<T>::Colour;  // Colour is treated as a typedef-name

  Colour foo ()  // OK
  {
  return this->RED;
  }
};

注意: 1998 版标准不允许 typename 与 using 声明一起使用,因此无法进行上述修复。请参阅 Accessing types from dependent base classesCWG11

【讨论】:

  • 在您的第一个示例中,您能否解释一下为什么该示例适用于template &lt;typename T&gt; class Sampletemplate &lt;typename T&gt; class Derived : public Sample&lt;T&gt;
【解决方案4】:

现在,有一个相关的问题:'using enum' in C++20

看起来 C++20 可以选择声明 using enum,从而最终允许直接访问枚举类的成员,如下所示 (source):

enum class fruit {
    orange,
    apple,
};

struct S {
  using enum fruit;             // OK, introduces orange and apple into S
};
void f() {
  S s;
  s.orange;                     // OK, names fruit​::​orange
  S::orange;                    // OK, names fruit​::​orange
}

当然,这意味着在S 内部,您也可以简单地使用orangeapple 而不是fruit::orangefruit::apple

【讨论】:

  • 它是2021。也许update the answer没有“编辑:”、“更新:”或类似的 - 问题/答案应该看起来好像是今天写的)?
  • 我看不出这有什么意义,尤其是因为内容会保持不变。是这样的吗?
猜你喜欢
  • 2014-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-23
  • 1970-01-01
  • 2011-02-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多