views:

352

answers:

8

I have this serious problem. I have an enumeration within 2 namespaces like this :

namespace FANLib {
namespace ERROR {

 enum TYPE {

  /// FSL error codes
  FSL_PARSER_FILE_IERROR,...

and somewhere else in my code, I use it like this :

FANLib::Log::internalLog(FSLParser::FILE_IERROR, file_ierror, true, FANLib::ERROR::FSL_PARSER_FILE_IERROR);

All compiles fine and well, but if I happen to include "windows.h", I get errors! The problem is in "WinGDI.h" which has this line :

#define ERROR               0

and makes the compiler think that, after FANLib::..., there is a zero! The error I get is :

Error 1 error C2589: 'constant' : illegal token on right side of '::'

Error 2 error C2059: syntax error : '::'

Error 3 error C2039: 'FSL_PARSER_FILE_IERROR' : is not a member of '`global namespace''

Argh!? Is there anything I can do about this, without having to change my namespaces due to some thoughtless #define? I have read in another post that I could #undef ERROR, but how safe is that?

Many thanks in advance.

+10  A: 

Generally, you should avoid using all-caps identifiers as they are used for macros. In this case, I'd rename the namespace.

(As a side note, <windows.h> #defines other stuff like GetPrinter and indeed it gets annoying. I usually go with #undef then. It also helps to only include <windows.h> in .cpp files and make sure the scope affected by the header is as small as possible.)

avakar
You make several very good points. Unfortunatly, I still only can give your answer one vote.
sbi
I would add the "standardly accepted convention" is that identifiers that are all caps are macros.
Martin York
Windows.h takes all "standardly accepted conventions", throws them out the window, and declares macros all over them. But yeah, good advice. Don't use all-caps for anything other than #defines, and don't allow windows.h to be visible in your headers.
jalf
+1  A: 

I think it won't be a problem if you #undef it. But, you would have to do it everywhere you use both your enum & windows.h. The best thing would be renaming your namespace.

erelender
+2  A: 

Renaming your namespace is the cleanest, safest, most interoperable solution.

Michael Foukarakis
+2  A: 

Hopping on the "rename your namespace" bandwagon, simply because ERROR is way too common and vague a name. Find something more descriptive.

suszterpatt
+1  A: 

You might want to refactor your code so that that #include only appears where necessary. The "correct" way might even involve making separate files and headers that include interfaces to the functions you will call from windows.h

However, if you just want a simple fix and are concerned about side-effects from #undef ERROR, just redefine ERROR after you are finished with your declaration:

#undef ERROR
namespace ERROR {
#define ERROR 0

You would have to do this everytime ERROR is referred to (and not in a string).

Having said that, you should be ok if you simply just undefined ERROR. It would only affect how the C preprocessor handles ERROR (or rather how it does not) from that point onwards.

By the way, I've generally seen names in all capital letters only be used to specify constants, not for types and namespaces. I'd reconsider my naming convention if I were you ..

lcv
Bad idea; it's not unheard of for Microsoft to change #define's in newer SDK versions. This happens even for constants (although ERROR likely won't be affected)
MSalters
You are right, it's not really good practice, and would easily lead to hard to debug side effects later on to assume that the value of a label will always be a given constant. But in my defense, it was not my first suggestion nor my last, and I never said anything about a good fix, I said it was a simple fix (or a quick fix) - and those types of fixes do usually cause hard to debug side-effects!
lcv
A: 

The best solution is to change your naming scheme to avoid all-caps, as others have suggested:

namespace FANLib {
  namespace Error {
    enum Type {
      /// FSL error codes
      FSL_Parser_File_IError, ...

Also off limits: identifiers that start with _ or __. (It's more complicated than that, but your life will be simpler if you just avoid all names that start with an underscore.)

Bill
A: 

If you do not use GDI then you could define NOGDI to suppress defining macros in WinGDI.h. Here you could find other useful options.

Kirill V. Lyadvinsky
A: 

Identifiers that begin with E and a digit or E and an uppercase letter should be treated as reserved, as such new macros could be added to <errno.h>.

Dan Moulding