6

Is the following legal according to the C++ standard? (If the answer differs from standard to standard, I would like to know that, too.)

#define VERY_OLD_COMPILER 1

#ifdef VERY_OLD_COMPILER
#define USING_NAMESPACE_STD enum { }
#else
#define USING_NAMESPACE_STD using namespace std
#endif

USING_NAMESPACE_STD;

int main(int argc, char *argv[]) {
// etc.

The goal is to define a macro that I can invoke at the top-level and follow with a semicolon, such that it has no effect. I am pretty sure stray semicolons at the top-level are not allowed (GCC complains about them, anyway), so simply defining an empty macro does not work.

Declaring an empty anonymous struct does not work because it needs a name, and I do not want to pollute the namespace.

Does an anonymous empty enum declaration (enum { }) do the trick? It works on all of the compilers I have tried, but of course that is not the same thing as being permitted by the spec.

Any other ideas/comments welcome. Well, anything other than "throw out that compiler". Believe me, I would love to.

Nemo
  • 70,042
  • 10
  • 116
  • 153
  • 6
    Why must you follow the macro call with a semicolon? Wouldn't this be trivial to solve if you didn't do that? – Greg Hewgill Jul 27 '11 at 00:06
  • 1
    @Greg: Personal preference. I am accustomed to invoking macros like `DO_STUFF(x,y);` inside a function, and I know how to write a no-op like that. I think `USING_NAMESPACE_STD` is a good name for this, and I think putting a semicolon at the end looks natural, so that is what I want. I am curious whether it is possible in the language as defined by the spec. – Nemo Jul 27 '11 at 00:14
  • 2
    I would agree with preferring the trailing semi-colon. There are times when you have to use statement-like macros that can't be followed by a semi-colon, but if you can avoid that, you should. – Michael Burr Jul 27 '11 at 00:18
  • 1
    Also many editors will not recognize the statement ending without a semicolon which will throw off your indentation. – c-urchin Jul 27 '11 at 00:25

7 Answers7

6

Looking at the latest public C++0x draft, it seems semicolons at top-level are allowed and ignored.

The grammar treats a translation-unit as a sequence of declarations, and amongst the various kinds of declarations there is an empty-declaration that is just a simple semicolon.

Pragmatic solution: considering that your VERY_OLD_COMPILER constant suggests that the whole thing is to be a part of a workaround for an older compiler, I'd just pick a solution that works with this compiler, be it standardised or not.

Alexander Gessler
  • 45,603
  • 7
  • 82
  • 122
  • Indeed, newer GCC's do not seem to mind the stray semicolon. Also, good point about it only needing to work on one compiler. Thanks for digging into the spec. – Nemo Jul 27 '11 at 00:38
4
#define USING_NAMESPACE_STD static int dummy##__LINE__
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Pity the poor programmer who decides to name a function "dummy13"? :-) I might be better off just picking 80 random characters... Is there really no way to do this without polluting the namespace? – Nemo Jul 27 '11 at 00:30
4

An empty enum is in fact illegal according to C++03:

7/3 Declarations:

In a simple-declaration, the optional init-declarator-list can be omitted only when declaring a class (clause 9) or enumeration (7.2), that is, when the decl-specifier-seq contains either a class-specifier, an elaboratedtype-specifier with a class-key (9.1), or an enum-specifier. In these cases and whenever a class-specifier or enum-specifier is present in the decl-specifier-seq, the identifiers in these specifiers are among the names eing declared by the declaration (as class-names, enum-names, or enumerators, depending on the syntax). In such cases, and except for the declaration of an unnamed bit-field (9.6), the decl-specifier-seq shall introduce one or more names into the program, or shall redeclare a name introduced by a previous declaration.

[Example:
enum { }; // ill-formed
typedef class { }; // ill-formed
—end example]

So I would agree with MSN's answer to declare a dummy enum, struct forward declaration, or typedef declaration with a name that is obviously not going to conflict with anything (throw a GUID in there for good measure). The nice thing about these things is that you can have the declaration show up more than once, and as long as it's the same as before there's no problem.

Community
  • 1
  • 1
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • I am sorry I can only accept one answer. (That is what I get for asking two questions.) – Nemo Jul 27 '11 at 00:45
2

Comeau says no:

> Comeau C/C++ 4.3.10.1 (Oct  6 2008 11:28:09) for
> ONLINE_EVALUATION_BETA2 Copyright 1988-2008 Comeau Computing.  All
> rights reserved. MODE:strict errors C++ C++0x_extensions
> 
> "ComeauTest.c", line 1: error: declaration does not declare anything  
> enum { };   ^
> 
> 1 error detected in the compilation of "ComeauTest.c".

You can use

#define USING_NAMESPACE_STD struct very_long_name_that_i_hope_doesnt_collide_because_if_it_does_oh_noes
MSN
  • 53,214
  • 7
  • 75
  • 105
  • +1 for good information, but I am more likely to accept an answer if it cites chapter and verse of a spec. – Nemo Jul 27 '11 at 00:15
0
#define VERY_OLD_COMPILER 1

#ifdef VERY_OLD_COMPILER
#define USING_NAMESPACE_STD typedef unsigned long uint32
#else
#define USING_NAMESPACE_STD using namespace std
#endif

USING_NAMESPACE_STD;

Edit: This should work also:

#define VERY_OLD_COMPILER 1

#ifdef VERY_OLD_COMPILER
#define USING_NAMESPACE_STD double fabs(double)
#else
#define USING_NAMESPACE_STD using namespace std
#endif

USING_NAMESPACE_STD;
André Puel
  • 8,741
  • 9
  • 52
  • 83
  • As I mentioned, that does not work because the stray semicolon is illegal. – Nemo Jul 27 '11 at 00:11
  • Sorry, my gcc didnt complain about that. Try the typedef solution. – André Puel Jul 27 '11 at 00:13
  • `int main();` isn't good C++. Unlike C, where it means "unspecified arguments", in C++ that means "no arguments", which may cause an error. – Ben Voigt Jul 27 '11 at 00:19
  • 'int main()' is just an example, just declare any thing that you are sure that exists. – André Puel Jul 27 '11 at 00:21
  • Your `typedef` assumes char is signed. The `main` solution declares a function with no arguments, but you could fix that with a proper prototype. But [is it legal to declare a prototype for main](http://stackoverflow.com/questions/5020362/declare-main-prototype)? – Nemo Jul 27 '11 at 00:21
  • Done, edited. Changed main for fabs, and typedef char to typedef unsigned long. – André Puel Jul 27 '11 at 00:33
0

Sorry, I forgot you needed to do it at the top level.

How about

extern int _;

? I don't know what undesirable side effects this would have, though I can't think of any.

Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
0
#define VERY_OLD_COMPILER 1

#ifdef VERY_OLD_COMPILER
#define USING_NAMESPACE_STD ;
#else
#define USING_NAMESPACE_STD using namespace std
#endif

USING_NAMESPACE_STD;

int main(int argc, char *argv[]) {
// etc.
Marvo
  • 17,845
  • 8
  • 50
  • 74