can an enumerant mask (obscure) a type in C++ ??

jochemspek
jochemspek used Ask the Experts™
on
Hi there, I just learnt the hard way that the following code won't compile and give the error (in MSVC)

error C2146: syntax error : missing ';' before identifier 'm_naabb'

#include "NAABB.h"

class RenderNode {
	public:
		/**
			@enum RenderComponents
			bitmask that determines which components are rendered
		*/
		typedef unsigned int ComponentMask;
		enum RenderComponents {
			NONE	= 0x0000,
			AABB	= 0x0001,
			NAABB	= 0x0002,
			AXES	= 0x0004,
			NORMALS	= 0x0008,
			ALL		= 0xFFFF
		};
                ComponentMask m_components;
		NAABB	          m_naabb;
};

Open in new window


(assuming all #included files are correct and there is a class named NAABB, for 'non-aligned-bounding-box'.
the intent of the enum is to be able to selectively render components of a node in a scenegraph where it would
be convenient if the components are named after the types to be rendered - ie to render member m_naabb
of type NAABB by masking in the NAABB enumerant)

Apparently this is because the NAABB in the enum RenderComponents 'obscures' the actual NAABB type,
because if I move the line NAABB m_naabb; to above the enum declaration, all is fine. I've never encountered
this before, and I don't quite understand why the compiler can't resolve this. Could an expert explain this to me ?

Thanks,

Jochem van der Spek
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
jkr
Top Expert 2012

Commented:
The problem seems to be the line

NAABB      = 0x0002,

with 'NAABB' apparently also being a class name, which makes the compiler choke, as it might interpret the line

NAABB                m_naabb;

as being an enumeration type instead of the class, as you mentioned - since within the class you're declaring, the name of the enumeration is not required to precede the name of it's members. Does using

::NAABB                m_naabb;

resolve the issue?

Author

Commented:
that would resolve the issue, but i'm still a bit nonplussed as to why this happens, surely an enumerant is not a type and hence the statement NAABB m_naabb only makes sense when NAABB is the class NAABB and not the enumerant. What is the reason for the compiler to choke here ?
Top Expert 2012
Commented:
Well, to be blunt - I am indifferent here. Strictly speaking, 'RenderComponents::NAABB' and 'NABB' (the class) are absolutely identical to the compiler from a C++ point of view, so this should yield a diffrent error or at least a warning when the 1st is introduced. Both symbols are ambiguous in that context. So, an error is OK, but the error message you are getting is not the correct one. Remember, at the scope of 'RenderNode', 'RenderComponents::NAABB' and 'NAABB' refer to the same enum member, with the 2st even generating a warning by VC++ mhen used inside 'RenderNode'.

Author

Commented:
'RenderComponents::NAABB' and 'N[A]ABB' (the class) are absolutely identical to the compiler from a C++ point of view

why is that ? the enumerant could not be used as a type and vice-versa, so the compiler could (and should ?) distinguish between both,
right ?

why would RenderComponents::NAABB and NAABB in <line> NAABB m_naabb; </line> refer to "the same enum member" ?
the latter could not possibly be used in that way, right ? and if that's the case, why doesn't the compiler issue a type error ?

oh, writing this (and testing to see what compiler error is issued when typing, say <line> 5 m_naabb; </line>) I realise the
compiler error is indeed that: error: expected `;' before 'm_naabb' means something in the line of "no type given before m_aabb"
which makes sense given that it sees NAABB as the enumerant, not the class.

Ok, so I understand the error, but I still find the compiler somewhat silly in not being able to distinguish between the two uses of NAABB.
otherwise it's quite smart though ;)

thanks for your answer !

J
evilrixSenior Software Engineer (Avast)

Commented:
>> why is that ?
Because the C++ standard says so. More specifically, it says this about name resolution:

"The name lookup rules apply uniformly to all names (including typedef-names, namespace-names and class-names) wherever the grammar allows such names in the context discussed by a particular rule. Name lookup associates the use of a name with a declaration of that name. Name lookup shall find an unambiguous declaration for the name. Name lookup may associate more than one declaration with a name if it finds the name to be a function name; the declarations are said to form a set of overloaded functions."

Putting some more context on this; the compiler is pretty dumb in so far as it doesn't generally consider the context. The reason for this is because at the time when it processes a symbol it may not have actually seen that symbol (just a declaration for it). This being the case, the compiler makes so assumptions about the symbol and so treats the names of classes and the names of enum values as the same thing (in a symbol sense, clearly not in a semantic sense); hence, you cannot have a class and an enum [value] with the same name in the same scope.

A simple solution for this is to wrap your enum in a struct.


struct NAABB{};

class RenderNode {
        public:
                /**
                        @enum RenderComponents
                        bitmask that determines which components are rendered
                */
                typedef unsigned int ComponentMask;
                struct RenderComponents {
                   enum type {
                        NONE    = 0x0000,
                        AABB    = 0x0001,
                        NAABB   = 0x0002,
                        AXES    = 0x0004,
                        NORMALS = 0x0008,
                        ALL             = 0xFFFF
                   };
                };
                //ComponentMask m_components;
                NAABB             m_naabb;
};

// access the enum values thus

RenderComponents::type rc = RenderComponents::NORMALS;

Open in new window

jkr
Top Expert 2012

Commented:
Thanks for helping out with the quotes from the standard, Rix ;o)
evilrixSenior Software Engineer (Avast)

Commented:
Any time :)

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial