一个包含枚举类型的 'using' 声明

11

using声明似乎不能与枚举类型一起使用:

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

using Sample::Colour;

无法工作!

我们需要为枚举类型的每个枚举器添加一个using声明吗?就像下面这样:

using sample::Colour::RED;

有没有其他的方法来做这件事? - yesraaj
1
虽然这并不是与你的问题直接相关,但我强烈建议你不要在枚举和常量中使用全大写标识符。在C/C++中,预处理器#定义通常都是全大写的,它们会混淆其他同名符号。 - Timo Geusch
在枚举类型中使用作用域解析运算符::(例如“sample :: Colour :: RED”)是编译器特定的扩展,而不是标准C ++。 - bk1e
要了解bk1e在非标准方面的说法,请参阅此Stack Overflow问题:Scope resolution operator on enums a compiler-specific extension? - jgawrych
2
@Jonathan Gawrych:这个链接的问题是从'09年的,那里的答案在'18年已经不适用了。 - AnT stands with Russia
4个回答

11

补充Steve Lacey的答案,原始代码的问题在于您引用了一个成员,但using声明本身不是成员声明:

7.3.3/6规定:

类成员的using声明必须是成员声明。

为了强调这一点,以下示例可以正常工作:

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

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

最后,正如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<T>”。
  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,因此上述修复方法不可行。请参见从依赖基类访问类型CWG11


1
在您的第一个示例中,您能否解释一下为什么样例不能与template <typename T> class Sampletemplate <typename T> class Derived:public Sample<T>一起使用? - geometrian

10

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

此外,您需要将枚举公开。

如果您正在尝试在同一类中使用枚举,以下是一个示例:

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

  void foo();
}

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

从类外部访问它的方式:

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

一个类除了其他功能外,还可以作为命名空间。因此,任何与普通命名空间一起使用但不适用于类的内容都是令人惊讶的。 - Peter - Reinstate Monica

5

C++标准,7.3.3.1:

在using声明中指定的成员名称被声明在出现using声明的声明区域中。[注意:只有指定的名称被这样声明;在using声明中指定枚举名称不会在using声明的声明区域中声明其枚举器。 —注]


1
C++标准还是歌剧之夜?(抱歉,我忍不住了)。 - Gorpik
2
你能解释一下这个习语吗?我的英语不是很好。 :) - Igor Semenov
2
我不确定标准是用英语编写的。看起来很像律师说法 :-) - Martin York
1
其实,我是指的是“C++标准”还是“歌剧之夜”? - Igor Semenov

5
到目前为止,有一个相关的问题:'using enum' in C++20
看起来C++20将有一个选项来进行using enum声明,从而最终允许直接访问枚举类的成员,就像这样(源代码):
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年。也许可以更新答案(不要包含"Edit:"、"Update:"或类似的字眼,问题/答案应该看起来像是今天写的)? - Peter Mortensen
我不明白这样做的意义,特别是因为内容完全没有改变。这是 Stack Overflow 的事吗? - RL-S

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接