Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A 'using' declaration with an enum

A using declaration does not seem to work with an enum type:

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

using Sample::Colour;

does not work!

Do we need to add a using declaration for every enumerators of enum type? Like below:

using sample::Colour::RED;
like image 206
yesraaj Avatar asked Jan 13 '09 07:01

yesraaj


People also ask

How do you declare and use enum?

An enum is defined using the enum keyword, directly inside a namespace, class, or structure. All the constant names can be declared inside the curly brackets and separated by a comma. The following defines an enum for the weekdays. Above, the WeekDays enum declares members in each line separated by a comma.

What is enum declaration?

An enumeration type declaration gives the name of the (optional) enumeration tag. And, it defines the set of named integer identifiers (called the enumeration set, enumerator constants, enumerators, or members). A variable of the enumeration type stores one of the values of the enumeration set defined by that type.

What is enum declaration in C++?

In C++ programming, enum or enumeration is a data type consisting of named values like elements, members, etc., that represent integral constants. It provides a way to define and group integral constants.

Can we declare variable in enum?

Enumerations are similar to classes and, you can have variables, methods, and constructors within them.


2 Answers

By now, there's a related question: 'using enum' in C++20.

It looks like C++20 will have the option make a using enum declaration, thus finally allowing direct access to an enum class' members, like this (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
}

Of course, that means that inside S, you will also be able to simply use orange and apple instead of fruit::orange and fruit::apple.

like image 147
RL-S Avatar answered Nov 02 '22 11:11

RL-S


To add to Steve Lacey's answer, the problem with the original code is that you refer to a member, but the using declaration is not itself a member declaration:

7.3.3/6 has:

A using-declaration for a class member shall be a member-declaration.

To highlight this, the following example does work:

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

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

Finally, as pointed out by Igor Semenov, even if you move the enum definition into a namespace, thereby allowing the using declaration, the using declaration will only declare the name of the enum type into the namespace (the 2003 standard reference is 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
}

Dependent Base Types

To allow for partial and explicit specializations, when the compiler parses a class template. it does not perform any lookups in dependent base classes. As a result, the following variation with Sample as a template does not compile:

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;
  }
};

The problem is that Derived::Colour is treated as an object by the compiler (14.6/2):

A name used in a template declaration or definition and that is dependent on a template-parameter is assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword typename.

Looking at the two conditions for the name to be a type:

  1. Lookup for Colour doesn't find a type because the dependent base Sample<T> is not searched.
  2. The name is not qualified by typename

The example therefore needs the typename keyword:

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;
  }
};

Note: The 1998 version of the standard didn't allow typename to be used with a using declaration and so the above fix was not possible. See Accessing types from dependent base classes and CWG11.

like image 42
Richard Corden Avatar answered Nov 02 '22 11:11

Richard Corden