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.
Related
In the bellow, the values of enum inside the class can be accessed by the name of the class.(I didn't even instantiate the class!)
class Shifting
{
public:
enum Value: char
{
UP, RIGHT, DOWN, LEFT
};
private:
Value value_;
};
std::cout << Shifting::RIGHT << std::endl; // 1
Does this mean that enum within a class is static?
If not, how to statically declare an enum?
This
enum Value: char
{
UP, RIGHT, DOWN, LEFT
};
this is a declaration of a type. It is not a data member of the enclosing class. The class has only this private data member.
Value value_;
of the enumeration data.
An enumerations declaration declares named enumerators. But they in turn are not data members of the enclosing class.
It is the same if you will declare a nested structure inside a class. For example
struct A
{
struct B
{
int x = 10;
};
B b;
};
Here is only one data member of the class A that is B b. The data member inside the structure declaration only provides the declaration of the structure B.
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.
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?
Consider a class template that implements a container which includes an option for choosing its storage place.
template<class T>
class Container {
public:
enum StorageOption {A,B};
Container(StorageOption opt_): option(opt_) {}
private:
StorageOption option;
};
Here StorageOption was chosen to be a member since it is only used in the class.
Now, to instantiate the class I would need to repeat the template parameter, like:
{
Container<int> c( Container<int>::A );
}
Is there a way to avoid repeating the parameter and at the same time have StorageOption being a member or is there a better way of implementing the option?
It is usually achieved by defining it in a base class.
class ContainerBase {
public:
enum StorageOption {A,B};
};
template<class T>
class Container : public ContainerBase{
public:
Container(StorageOption opt_): option(opt_) {}
private:
StorageOption option;
};
Container<int> c( ContainerBase::A );
I have been battling with this problem myself and I don't really like the need for a base class as well as how you need to repeat the base class specifier when wanting to use enum classes. I came up with this solution:
namespace FuncEnum{
enum class FuncNeighbor{
FLOOR, CEILING, SELF
};
enum class FuncDirection{
BACK, FRONT, BACKNFRONT
};
enum class FuncVar{
X, Y
};
} using namespace FuncEnum;
template<typename... Types>
class Func {};
This way you can have globally available enum classes with minimal specification. It's not likely that collision happens between < class nickname > < enum class name > but even if there were, the using declaration should shadow (?) whatever global identifier about to interfere (which, in a peculiar case can be undone again with another using declaration).
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.