473,401 Members | 2,127 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,401 software developers and data experts.

Query regarding enums in switch/case statements.

Hi. I have a c++ project that is basically a set of implementation
hiding classes, so that we can convert a static lib with a lot of
dependancies into a dynamic lib with less dependancies, so that users
of the lib dont require all the development tools we used to develop
the lib.

I have noticed something strange, and was wondering if its a C++
feature, or a implementation specific bug.

I have a function like this:

CheckerErrorId CCheckerError::GetErrorId()
{
ECheckerError ce = pimpl->getC_ErrorId();
switch (ce)
{
case CINFO:
return CINFO;
case CHWARNING_bus_blocked_yet:
return CHWARNING_bus_blocked_yet;
case CHWARNING_no_output_message_defined:
return CHWARNING_no_output_message_defined;
// Rest of list omitted.
default:
return CHERROR_unknown;
}
}

This function converts the internally used ECheckerError enum (as
defined in the original static libs header files) into the equivalent
CheckerErrorId as defined in my dynamic lib.

However the compiler seems to treat ce as if it were a CheckerErrorId
rather than a ECheckerError. pimpl->getC_ErrorId() could return CINFO,
but the switch statement seems to skip to the case that CINFO matches
in the list of Checker.

Internal enum looks something like this (most of it removed):

enum ECheckerError {
CHERROR_unknown,
CHWARNING_bus_blocked_yet,
CHWARNING_no_output_message_defined,
CINFO
};

CheckerErrorId looks like :
enum CheckerErrorId {
CHERROR_unknown,
CHWARNING_bus_blocked_yet,
CHWARNING_bus_undefined,
CHWARNING_no_output_message_defined,
TPCHWARNING_wrong_generalTimeout_time,
CINFO
};

So if pimpl->getC_ErrorId() returns CINFO, then it jumps down to the
case for CHWARNING_no_output_message_defined.

If we use if and == then the problem remains. The compiler seems to
ignore the fact that ce is a ECheckerError, and treats it like it were
a CheckerErrorId, or perhaps as if they were merely #defines or
something, simply replacing them by their integer representations!

My question is, is this standard c++ behavior or a possible compiler
bug?

Thanks a lot gurus.

Kurt

Mar 23 '07 #1
7 5243
On Mar 23, 9:23 am, "Kurt" <kurt.haeus...@gmail.comwrote:
Hi. I have a c++ project that is basically a set of implementation
hiding classes, so that we can convert a static lib with a lot of
dependancies into a dynamic lib with less dependancies, so that users
of the lib dont require all the development tools we used to develop
the lib.

I have noticed something strange, and was wondering if its a C++
feature, or a implementation specific bug.

I have a function like this:

CheckerErrorId CCheckerError::GetErrorId()
{
ECheckerError ce = pimpl->getC_ErrorId();
switch (ce)
{
case CINFO:
return CINFO;
case CHWARNING_bus_blocked_yet:
return CHWARNING_bus_blocked_yet;
case CHWARNING_no_output_message_defined:
return CHWARNING_no_output_message_defined;
// Rest of list omitted.
default:
return CHERROR_unknown;
}

}

This function converts the internally used ECheckerError enum (as
defined in the original static libs header files) into the equivalent
CheckerErrorId as defined in my dynamic lib.

However the compiler seems to treat ce as if it were a CheckerErrorId
rather than a ECheckerError. pimpl->getC_ErrorId() could return CINFO,
but the switch statement seems to skip to the case that CINFO matches
in the list of Checker.

Internal enum looks something like this (most of it removed):

enum ECheckerError {
CHERROR_unknown,
CHWARNING_bus_blocked_yet,
CHWARNING_no_output_message_defined,
CINFO

};

CheckerErrorId looks like :
enum CheckerErrorId {
CHERROR_unknown,
CHWARNING_bus_blocked_yet,
CHWARNING_bus_undefined,
CHWARNING_no_output_message_defined,
TPCHWARNING_wrong_generalTimeout_time,
CINFO

};

So if pimpl->getC_ErrorId() returns CINFO, then it jumps down to the
case for CHWARNING_no_output_message_defined.

If we use if and == then the problem remains. The compiler seems to
ignore the fact that ce is a ECheckerError, and treats it like it were
a CheckerErrorId, or perhaps as if they were merely #defines or
something, simply replacing them by their integer representations!

My question is, is this standard c++ behavior or a possible compiler
bug?
Obviously you can't have two enum constants with the same name in the
same scope. So, for instance:

enum E1 { A };
struct S
{
enum E2 { A }; // Ok: different scope
};
enum E3 { A }; // Error: A already exists in this scope

In your function since the compiler would complain if your return
value type wasn't convertible to a CheckerErrorId, apparently the enum
constants for CheckerErrorId are in scope but those for ECheckerError
are not (but then how is the enum type ECheckerError unqualified? Is
that your real code or did you [incorrectly] modify it for this
post?).

Please clarify, and check out this FAQ on posting code that doesn't
work properly:

http://www.parashift.com/c++-faq-lit...t.html#faq-5.8

Cheers! --M

Mar 23 '07 #2
On Mar 23, 2:44 pm, "mlimber" <mlim...@gmail.comwrote:
Obviously you can't have two enum constants with the same name in the
same scope. So, for instance:

enum E1 { A };
struct S
{
enum E2 { A }; // Ok: different scope
};
enum E3 { A }; // Error: A already exists in this scope

In your function since the compiler would complain if your return
value type wasn't convertible to a CheckerErrorId, apparently the enum
constants for CheckerErrorId are in scope but those for ECheckerError
are not (but then how is the enum type ECheckerError unqualified? Is
that your real code or did you [incorrectly] modify it for this
post?).

Please clarify, and check out this FAQ on posting code that doesn't
work properly:
Thanks a lot for the fast response. Thats the real code, except I have
taken out most of the enum entries. As far as scope goes,
CheckerErrorId is defined in a namespace, ECheckerError not, but I
think they are both in scope. Seems like at compile time theres no
issue, why should the compiler expect ECheckerError to be convertible
to a CheckerErrorId? Theres no explicit assignment or comparison
between the two.

Surely the type safety mechanism makes it clear that the only thing
following the case can be a ECheckerError, and the only things that
can be returned are CheckerErrorIds?

The issue only really appears at run time, when the type of ce seems
to be ignored.

Or perhaps the error is that my compiler neglects to detect any scope
collision.

Ahh it is the namespace thing isnt it. If I am "using" the namespace,
then the ECheckerError enums should be preceeded by a :: right? Heh
amazing how typing out a newsgroup article helps one think things
over.

But still... Typesafety should have provided the compiler and/or
runtime system with sufficient information to distinguish which is
which.. ce is declared as a ECheckerError, the compiler shouldnt even
consider that anything following a case statement is anything else.

Mar 23 '07 #3
On Mar 23, 10:10 am, "Kurt" <kurt.haeus...@gmail.comwrote:
On Mar 23, 2:44 pm, "mlimber" <mlim...@gmail.comwrote:
Obviously you can't have two enum constants with the same name in the
same scope. So, for instance:
enum E1 { A };
struct S
{
enum E2 { A }; // Ok: different scope
};
enum E3 { A }; // Error: A already exists in this scope
In your function since the compiler would complain if your return
value type wasn't convertible to a CheckerErrorId, apparently the enum
constants for CheckerErrorId are in scope but those for ECheckerError
are not (but then how is the enum type ECheckerError unqualified? Is
that your real code or did you [incorrectly] modify it for this
post?).
Please clarify, and check out this FAQ on posting code that doesn't
work properly:

Thanks a lot for the fast response. Thats the real code, except I have
taken out most of the enum entries. As far as scope goes,
CheckerErrorId is defined in a namespace, ECheckerError not, but I
think they are both in scope. Seems like at compile time theres no
issue, why should the compiler expect ECheckerError to be convertible
to a CheckerErrorId? Theres no explicit assignment or comparison
between the two.

Surely the type safety mechanism makes it clear that the only thing
following the case can be a ECheckerError, and the only things that
can be returned are CheckerErrorIds?

The issue only really appears at run time, when the type of ce seems
to be ignored.

Or perhaps the error is that my compiler neglects to detect any scope
collision.

Ahh it is the namespace thing isnt it. If I am "using" the namespace,
then the ECheckerError enums should be preceeded by a :: right? Heh
amazing how typing out a newsgroup article helps one think things
over.

But still... Typesafety should have provided the compiler and/or
runtime system with sufficient information to distinguish which is
which.. ce is declared as a ECheckerError, the compiler shouldnt even
consider that anything following a case statement is anything else.
Does your compiler allow this:

enum E1 { A };
namespace NS { enum E2 { A }; }
using namespace NS;

It shouldn't because A is ambiguous. Hence, I don't think you've
assessed your scope problem correctly. Please post a *complete* but
*minimal* sample (i.e., one that we can cut and paste into our editors
unchanged) that demonstrates your problem.

In any case, this should work fine:

enum E1 { A, B };
namespace NS { enum E2 { A, B }; }

NS::E2 Foo( E1 e1 )
{
switch( e1 )
{
case NS::A: // Not ::A
return NS::A;
default:
return NS::B;
}
}

The reason is that enums are convertible to and therefore comparable
as ints, so the compiler won't complain about the type in such a
switch statement. See also:

http://www.parashift.com/c++-faq-lit...html#faq-29.19
http://www.parashift.com/c++-faq-lit...html#faq-29.20

Cheers! --M

Mar 23 '07 #4
On Mar 23, 3:49 pm, "mlimber" <mlim...@gmail.comwrote:
Does your compiler allow this:

enum E1 { A };
namespace NS { enum E2 { A }; }
using namespace NS;

It shouldn't because A is ambiguous. Hence, I don't think you've
assessed your scope problem correctly. Please post a *complete* but
*minimal* sample (i.e., one that we can cut and paste into our editors
unchanged) that demonstrates your problem.
Heh my compiler has no problem at all with it. (MS VC++ 2005 without
the buggy SP1)

However when I do something like:

enum E1 { C, A, B };
namespace NS { enum E2 { A, B, C, D, E }; }
using namespace NS;

E2 Foo( E1 e1 )
{
switch( e1 )
{
case A:
return A;
default:
return B;
}
}

Which is almost analogous to my situation, then I get ambiguous symbol
errors. Still trying to work out exactly why my real code doesnt
generate this error...

Anyway, it was no real problem, I just renamed all the entries in my
CheckerErrorId by prefixing them with something so they dont clash
with the ECheckerError.

Thanks a lot for your comments.

OK! Now I have the analagous example: The difference was that Foo is a
member of a class.

enum E1 { C, A, B };
namespace NS { enum E2 { A, B, C, D, E };
class Bar
{
virtual E2 Foo( E1 e1);
};
}
using namespace NS;

E2 Bar::Foo( E1 e1 )
{
switch( e1 )
{
case A:
return A;
default:
return B;
}
}

This compiles fine for me, with no ambiguous symbol errors. Compiler
bug?

Mar 23 '07 #5
enum E1 { C, A, B };
namespace NS { enum E2 { A, B, C, D, E };
class Bar
{
virtual E2 Foo( E1 e1);
};}

using namespace NS;

E2 Bar::Foo( E1 e1 )
{
switch( e1 )
{
case A:
return A;
default:
return B;
}
}

This compiles fine for me, with no ambiguous symbol errors. Compiler
bug?
Hmm GCC on linux has no problem with it either, what difference here
does making Foo a class member make?

Not really trying to solve any problems here as much as just improve
my understanding of c++.

Mar 23 '07 #6
Kurt wrote:
>enum E1 { C, A, B };
namespace NS { enum E2 { A, B, C, D, E };
class Bar
{
virtual E2 Foo( E1 e1);
};}

using namespace NS;

E2 Bar::Foo( E1 e1 )
{
switch( e1 )
{
case A:
return A;
default:
return B;
}
}

This compiles fine for me, with no ambiguous symbol errors. Compiler
bug?

Hmm GCC on linux has no problem with it either, what difference here
does making Foo a class member make?

Not really trying to solve any problems here as much as just improve
my understanding of c++.
Actually, the difference is that Foo is (indirectly) enclosed by
the namespace NS, causing a lookup for the enumerator constants A
and B from *within* the namespace (more precisely, from a subscope
within that namespace).

As E2 is defined within the namespace its enumerators shadow
identically named enumerators in namespaces (including the global
namespace) enclosing NS.

Mar 23 '07 #7
On Mar 23, 11:32 am, "Kurt" <kurt.haeus...@gmail.comwrote:
On Mar 23, 3:49 pm, "mlimber" <mlim...@gmail.comwrote:
Does your compiler allow this:
enum E1 { A };
namespace NS { enum E2 { A }; }
using namespace NS;
It shouldn't because A is ambiguous. Hence, I don't think you've
assessed your scope problem correctly. Please post a *complete* but
*minimal* sample (i.e., one that we can cut and paste into our editors
unchanged) that demonstrates your problem.

Heh my compiler has no problem at all with it. (MS VC++ 2005 without
the buggy SP1)
Mea culpa. I should have added a use of A after it, like:

int main()
{
return A;
}

Now Comeau, VC++ '05, EDG, and gcc give an error.
OK! Now I have the analagous example: The difference was that Foo is a
member of a class.

enum E1 { C, A, B };
namespace NS { enum E2 { A, B, C, D, E };
class Bar
{
virtual E2 Foo( E1 e1);
};}

using namespace NS;

E2 Bar::Foo( E1 e1 )
{
switch( e1 )
{
case A:
return A;
default:
return B;
}
}

This compiles fine for me, with no ambiguous symbol errors. Compiler
bug?
Ok, now we're down to the real problem. As Michael Mehlich said, the
issue is not that Foo is a member function but that Foo is in the same
namespace with E2, which silently hides E1's constants since their
outside the namespace. (PC-Lint by Gimpel catches things like this,
BTW. You might want to check it out.) And like I said previously,
there's no type error here because e1 is compared *as an int* against
the *integer values* of E2's A and B but the proper enum type is still
returned.

Cheers! --M

Mar 23 '07 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
by: wiredog | last post by:
I am struggling rewriting my query from MS Access' IIF, Then to SQL Servers TSQL language. I am hoping some one can give me some guidance. I believe I have the first portion of the query correct...
27
by: Mark A. Gibbs | last post by:
i have been toying with the idea of making my enums smarter - ie, more in line with the rest of the language. i haven't tested it yet, but what i came up with is a template like this: template...
10
by: clueless_google | last post by:
hello. i've been beating my head against a wall over this for too long. setting the variables 'z' or 'y' to differing numbers, the following 'if/else' code snippet works fine; however, the ...
17
by: prafulla | last post by:
Hi all, I don't have a copy of C standard at hand and so anyone of you can help me. I have always wondered how switch statements are so efficient in jumping to the right case (if any)? Can...
2
by: Simon Elliott | last post by:
I have some legacy C++ code which requires some enums to be 1 or 2 bytes in size. I'd ideally like to be able to specify that a few carefully selected enums are a particular size. By default,...
1
by: MariuszC | last post by:
Hello, I have used some library where is defined enum like: typedef enum Enum1 { ENUM1_1, ENUM1_2, ENUM1_3, ENUM1_4, ENUM1_5 }; In my code I have defined: typedef enum Enum2 { ENUM2_1,...
7
by: alunharford | last post by:
When I'm coding in Java, I might write the following (contrived) code: boolean b = SomeMethod(); switch (b) { case true: return 1; case false: return 0; default: throw new InternalError();
5
by: sam_cit | last post by:
Hi Everyone, I read somewhere that there are some compile time operations behind switch-case, which is why it can work for cases which evaluates to an integer or character and not strings and...
10
by: =?utf-8?b?QXNiasO4cm4gU8OmYsO4?= | last post by:
I came over this code which puzzled me. Isn't the enum supposed to have an identifier? enum { BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */ BT_OPEN, BT_BOUND,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.