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.
Related
The STL <memory> header (MSVC implementation) contains a class called:
template <class _Ty> class _Ref_count_obj2 : public _Ref_count_base
This class has a member:
union {
_Wrap<_Ty> _Storage;
};
where _Wrap is defined as:
template <class _Ty>
struct _Wrap {
_Ty _Value; // workaround for "T^ is not allowed in a union"
};
From my understanding, this code is designed to hold an object of type _Ty following its construction via the new operator. However I can't figure out why this was done; it seems like using a struct instead of a struct inside a union would work just as well.
Can anyone explain the reasoning behind this? Also, can anyone explain the comment in the _Wrap definition?
First, embedding the _Storage member in a union will prevent default destruction of that object (which is, more than likely, a non-trivial type); this appears to be essential, as the class involved is a reference counter. (By default, unions have a deleted destructor; see, for example: Is a Union Member's Destructor Called .)
Second, using an anonymous union 'moves' the _Storage identifier into the enclosing scope, thus removing any need for X.-style notation (if the union were to be named X). From cppreference:
Members of an anonymous union are injected in the enclosing scope (and
must not conflict with other names declared there).
Last, the need to wrap the union's member into a templated structure is so that the class will work with reference types, which are not allowed in unions. To check this last part out, try the following code with the commented-out lines made active:
template <class _Ty>
struct _Wrap {
_Ty _Value; // workaround for "T^ is not allowed in a union"
};
template<class T>
class bob {
public:
bob(T t) : uncle{t}//, aunty(t)
{
}
private:
union {
_Wrap<T> uncle;
};
// union {
// T aunty;
// };
};
int main()
{
int i = 42;
bob<int&> b{ i }; // Note: Template uses a REFERENCE type
return 0;
}
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 am using visual studio 2010, and can't quite get, how is this class wrong (syntax error : identifier 'EnumType ') and won't compile:
class BrokenClassWithEnum
{
private:
void useEnum (EnumType enumType); //syntax error : identifier 'EnumType '
public:
enum EnumType
{
VAL1,
VAL2,
VAL3
};
}
And this is OK:
class WorkingClassWithEnum
{
public:
enum EnumType
{
VAL1,
VAL2,
VAL3
};
private:
void useEnum (EnumType enumType);
}
What happened to the class scope?
I don't think the order of definition (not declaration) matters but a forward declaration will resolve this error - at least in MSVC++ 6. Outside of MSVC++ 6 you should specify a storage type to forward declare an enum (the requirement for specifying the storage type in a forward enum was in the C++0x standard)
NOTE: VC++ 6 will allow the storage type to be omitted, but if you are forward declaring an enum, you should declare the storage type (SEE BELOW):
This will resolve the error in VC++6. However, VC++6 does not appear to support a STORAGE TYPE for an enum inside a class as required by the C++0x standard:
class BrokenClassWithEnum {
public:
enum EnumType;
private:
void useEnum (EnumType enumType);
public:
enum EnumType {
VAL1,
VAL2,
VAL3
};
};
Normally I.E. within a C++0x compliant compiler you would use something like:
class BrokenClassWithEnum {
public:
enum EnumType : int;
private:
void useEnum (EnumType enumType);
public:
enum EnumType : int {
VAL1,
VAL2,
VAL3
};
};
NOTE:Forward declaration of enums is possible in some but not all C++ versions:
Forward declaring an enum in c++
In C++ any referenced non-built-in name must have been declared somewhere earlier.
It might appear that this rule has an exception for class definitions, because the following works fine:
struct S
{
void foo() { cout << x_ << endl; }
int x_;
S(): x_( 42 ) {}
};
However, the rule about declaration-before-use applies to the transformed code
struct S
{
inline void foo();
int x_;
inline S();
};
void S::foo() { cout << x_ << endl; }
S::S() : x_( 42 ) {}
which is what the compiler "proper" sees. And here there is no use of anything that hasn't already been declared.
The proper C++03 solution to your problem is to define the enumeration type before its first use. With C++11 you can alternatively forward-declare it, but then an underlying type must be specified,
C++11 §7.2/3:
“An opaque-enum-declaration is either a redeclaration of an enumeration in the current scope or a declaration
of a new enumeration. [Note: An enumeration declared by an opaque-enum-declaration has fixed underlying
type and is a complete type. The list of enumerators can be provided in a later redeclaration with an enum-
specifier. —end note ] A scoped enumeration shall not be later redeclared as unscoped or with a different
underlying type. An unscoped enumeration shall not be later redeclared as scoped and each redeclaration
shall include an enum-base specifying the same underlying type as in the original declaration.”
Within the class definition itself, items must appear in order (with dependent items appearing before the items that depend on them) like they do at any other scope. Inside a class method body (even if inlined) the entire definition of the class is available.
I believe member variables can be accessed before declarations within the class because class validation or compilation is done in two pass.
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.