Defining a top-level no-op in C++?
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, anythin开发者_Go百科g other than "throw out that compiler". Believe me, I would love to.
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 declaration
s, 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.
#define USING_NAMESPACE_STD static int dummy##__LINE__
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.
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
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.
#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;
#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.
精彩评论