Suppose we have an enum class:
enum class E
{
constant
};
To refer to the enumerator in E, we can write E::constant, while the following is illegal:
E e;
e.constant;
But consider this:
struct S
{
enum {constant};
};
Both S::constant and s.constant are legal, wouldn't it be more consistent to allow e.constant for an enum class? Is the inability intentional?
Related
I'm working on a problem where part of the code looks like the one below:
class x
{
type t;
public:
enum type { A, B, C, D};
};
g++ says type does not name a type. I tried changing type t to x::type t or compiling with C++11 to no avail.
It's a simple problem so there's no linking, aka, I didn't include any header file.
Please enlighten me.
You have to declare type before you create a variable of type type. If you move type 't' after the declaration of type in your code it will fix the error. Change this
class x
{
type t;
public:
enum type { A, B, C, D};
};
to this
class x
{
public:
enum type { A, B, C, D};
private:
type t;
};
and it will work properly.
The compiler doesn't know type is an enum because it was used before it was declared.
Try this:
class x
{
public:
enum type { A, B, C, D};
private:
type t;
};
I need to access a public enum belonging to another class, to simplify, something like this:
class obj
{
public:
enum Type
{
t1,
t2,
t3
};
Type type;
};
class otherObj
{
public:
void setType(obj* o);
};
void otherObj::setType(obj* o)
{
o->type = obj::Type::t1;
return;
}
How do I do that, because the line
o->type = obj::Type::t1;
throws out an error:
obj::Type is not a class or namespace.
obj::t1
obj::t2
obj::t3
Aren't C++ enums great? The values fall into the scope above them even though the enum can be treated as a type.
You either just use
obj::t1;
or specify the class attribute with your enum declaration
enum class Type {
t1,
t2,
t3
};
In C++03, the enum values belong to the enclosing scope. Hence, replacing obj::Type::t1 with obj::t1 would work for you.
This is somewhat counter-intuitive, and is addressed by the enum class feature in C++11, which puts the enum values directly in the enum scope. Thus, if you use enum class in a C++11 compliant compiler, then you would be able to use obj::Type::t1 as you are currently doing.
I'm trying to build a class such that its subclasses will have a C++11 enum class attribute, with an associated setter/getter:
class Base {
public:
enum class MyEnum {
A,
B
} my_enum;
Base() : my_enum(MyEnum::A) {}
MyEnum get() { return my_enum; }
void set(const MyEnum &ME) { my_enum = ME; }
};
class Derived : public Base {
public:
Derived(): Base() {
my_enum = MyEnum::B;
}
};
int main(int argc, char *argv[])
{
Derived Deriv;
// No problems!
Deriv.get() == Derived::MyEnum::B;
return 0;
}
so far, so good!
However, I would like derived classes to be able to re-define the MyEnum enumeration class, while not having to re-implement the setter/getter/attribute all the time:
// Base as before
class Derived : public Base {
public:
enum class MyEnum {
C,
D
}; // intention: to override Base's "my_enum" attribute
Derived(): Base() {
my_enum = MyEnum::C;
// ERROR: cannot convert 'Derived::MyEnum' to 'Base::MyEnum'
}
};
int main(int argc, char *argv[])
{
Derived Deriv;
// ERROR: no match for 'operator==' for types 'Base::MyEnum' and 'Derived::MyEnum'
Deriv.get() == Derived::MyEnum::C;
return 0;
}
I understand what the problem is; I'm just looking for the cleanest way to be able to reuse code for this case.
Preferably only through inheritance (or rather, the functionality should be available to Derived() classes solely by the act of deriving from Base()).
Any suggestions?
You could make Base a template, parameterised by the enum type, and use a traits class to provide a "default" enum type which can be specialized by derived types.
template<typename T>
struct MyEnumTraits
{
enum class type {
A,
B
};
static const type default_value = type::A;
};
template<typename T = void>
class Base {
public:
typedef typename MyEnumTraits<T>::type MyEnum;
MyEnum my_enum;
Base() : my_enum(MyEnumTraits<T>::default_value) {}
MyEnum get() { return my_enum; }
void set(const MyEnum &ME) { my_enum = ME; }
};
class Derived;
template<>
struct MyEnumTraits<Derived>
{
enum class type {
C,
D
};
static const type default_value = type::C;
};
class Derived : public Base<Derived> {
// ...
But now different derived types will have different base classes, which is probably not what you want. You could solve that by keeping the non-template Base and moving the getter and setter into an intermediate class template that derivecs from Base and then the derived types derive from that.
class Base { ... };
template<typename T = void> class GetterSetterImpl : public Base { ... };
class Derived : public GetterSetterImpl<Derived> { ... };
The compiler is right: although the enumerations Base::MyEnum and Derived::MyEnum are defined in classes connected through inheritance, the enumerations themselves are not considered related. They just happen to have the same unqualified name, which means nothing to the compiler: as far as the compiler is concerned, the two enum types are unrelated.
If you think about the way the enums are implemented under the hood, this makes sense: despite being strongly typed, the enums remain small integral constants. Since the two are unrelated, Base::MyEnum::A would have the same value as Derived::MyEnum::C, and there would be nothing at runtime letting you distinguish between the two values.
Besides dumping all enumeration values into the enum of the base class (which kills opportunities to extend outside your own library) there is little you can do: C++ enumerations do not support inheritance, and are generally not very flexible.
This is a bad idea and is not going to work.
Language level You cannot redefine stuff in C++. You can only hide (not completely) stuff behind new, unrelated stuff with the same name. You can also override a virtual function by giving it a new implementation, while keeping its signature.
Design level Your base class defines a contract which derived classes must adhere to. If Base::get() returns a MyEnum {A, B}, then every derived class must have a get() that returns a MyEnum {A, B}. That's what inheritance is all about (and not code reuse, or not just code reuse at any rate).
You may be able to achieve code reuse by making your class into a template instead of relying on inheritance.
In my project, I have an enum defined in a class, that is used throughout that class. During refactoring, that enum was moved to another class. So I simply typedefed it in my original class, like this:
class A {
public:
enum E {e1, e2};
};
class B {
public:
typedef A::E E;
};
Now variable definitions, return values, function params, etc. work perfectly. Only when I want to access the values of the enum inside my second class, I still have to qualify them with the surroundig class's name,
e.g. E e = A::e1;
Is there a way to avoid this, or do I have to copy that into every occurance of the enum values?
You put each enumeration into a nested class that you can typedef within your own class:
class A {
public:
struct E { enum EnumType { e1, e2 } };
};
class B {
public:
typedef A::E E;
};
Then it's just E::EnumType instead of E but you get full auto-importation.
If you're not above using c++11, you could have a look at enum classes.
Previously I've defined enumerated types that are intended to be private in the header file of the class.
private:
enum foo { a, b, c };
However, I don't want the details of the enum exposed anymore. Is defining the enum in the implementation similar to defining class invariants?
const int ClassA::bar = 3;
enum ClassA::foo { a, b, c };
I'm wondering if this the correct syntax.
C++ doesn't have forward declarations of enums, so you can't separate enum "type" from enum "implementation".
The following will be possible in C++0x:
// foo.h
class foo {
enum bar : int; // must specify base type
bar x; // can use the type itself, members still inaccessible
};
// foo.cpp
enum foo::bar : int { baz }; // specify members
No, enum ClassA::foo { a, b, c }; is not correct syntax.
If you want to move the enum out of the header and into the implementation (.cpp) file, then just do that. If you want to use the enum for parameter types of methods of the class, then you cannot move it, so just leave it private.