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.
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.
#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.
Related
You can't forward declare an enum in C++, but you can in C.
For a C code-base that uses some C++ code, is there a way to use a forward declared enum in C that doesn't cause errors when that header is used in C++ (within an extern "C" {..} block)?
Example:
extern "C" {
enum MyEnum;
}
int main() { return 0; }
GCC gives the error:
error: use of enum ‘MyEnum’ without previous declaration
enum MyEnum;
^~~~~~
Clang also fails with:
error: ISO C++ forbids forward references to 'enum' types
enum MyEnum;
To give some context, this is a mainly C code-base where a small C++ module happens to include a header for C code. I can do some hack to make C++ ignore the enum, but I would like to know if its possible for C++ to use C headers in this case.
Update: It's been noted the official C specification doesn't support this. However, it seems this is a de facto standard among some of the most widely used compilers: GCC, Clang, and Microsoft Visual C++.
You can forward-declare enum in C++ starting from C++11. It's called "opaque declaration" rather than "forward declaration" because technically it results in a bit different effect: the size of the enum is known after its opaque declaration, while with the forward-declared types that's not the case.
However, from the daily perspective it's the same idea: you can just declare your enum and use it further in the code. From cppreference:
enum-key attr(optional) nested-name-specifier(optional) identifier enum-base(optional) ;(2) (since C++11)
2) Opaque enum declaration: defines the enumeration type but not its enumerators: after this declaration, the type is a complete type and its size is known. Note: an explicit specialization declaration of a scoped enumeration member of a class template is the only case where nested-name-specifier appears before identifier (since C++14)
Forward declaration of enums in C just makes no sense. Enums in C only introduce integral enumeration constants. They don't introduce any types you would want to use. Each enum type is an unspecified integral type, compatible with all other integral types, so there isn't any type safety at all.
typedef enum e12 { ONE, TWO } e12;
typedef enum e34 { THREE, FOUR } e34;
int main () {
e12 one = ONE;
e34 three = THREE;
one = three;
three = ONE;
return one + three;
}
This C program compiles cleanly with GCC on -Wall -Wextra -Wpedantic (it won't work as a C++ program of course).
So a useful portable cross-language solution would be
#ifdef __cplusplus
enum MyEnum : int;
#else
typedef int MyEnum; // 'enum MyEnum' would give no improvement over this
#endif
This can be done in C++11, (see #vasiliy-galkin's answer), an example of how this can work for shared C/C++ headers.
C header forward declaring MyEnum.
#ifdef __cplusplus
extern "C" {
#endif
enum MyEnum
#ifdef __cplusplus
: int
#endif
;
#ifdef __cplusplus
}
#endif
Is it possible to remove standard features from C++
//Undefine some function from the standard like classes
class someclass
{
someclass(){
//Whatever
}
};
then get the error
"class undeclared identifier"
Not that I recommend it but you can use pre-processor macros to undefine anything you want.
If you compile the program below, you will get lots of errors.
#define vector
#include <vector>
int main()
{
vector<int> a;
}
You don't need the #define vector in the file. You can define it in the command used to invoke the compiler.
Note that using the above trick makes your program subject to undefined behavior:
From the C++11 Standard:
17.6.4.3 Reserved names
...
2 If a program declares or defines a name in a context where it is reserved, other than as explicitly allowed by this Clause, its behavior is undefined.
17.6.4.3.1 Macro names [macro.names]
1 A translation unit that includes a standard library header shall not #define or #undef names declared in any standard library header.
2 A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table [tab:identifiers.special], or to the attribute-tokens described in [dcl.attr].
In the following code there are no errors or warnings at compile/link-time
enum E;
enum E;
int _tmain(int argc, _TCHAR* argv[]){ }
Is it VS2010 bug?
Your code compiles with VC++ 2010 and later by virtue of MS language extensions
that you can disable with the compiler flag /Za.
At first sight,
enum E;
enum E;
looks just like two forward declarations of enum E. In that light, the duplication does not appear
relevant. N forward declarations of something are no more or less legal than one, so the effect of
enabling the MS extensions (/Ze) would appear to include enabling forward enum declarations,
which are illegal per C++03 or C++11.
But that appearance is misleading, as the following program shows:
#include <iostream>
enum E;
//enum E;
enum E e;
int main()
{
std::cout << (e == 0) << std::endl;
return e;
}
This also compiles clean with VC++ 2010 or later, proving that
the compiler parses enum E; not as forward declaration of E but as a definition.
The language extension here is that enum E;, on first sight, is equated with enum E {}.
If we uncomment //enum E; in the program, it still compiles clean, showing that on second sight
and subsequently, enum E; is not again parsed as a definition, just as a redeclaration of E.
VC++ 2013 supports the C++11 concepts of scoped and based enums. With extensions disabled,
it will compile and reject declarations as indicated by this piece of code:
enum UnscopedBasedEnum : int; // :)
enum UnscopedBasedEnum : int; // :)
UnscopedBasedEnum ube; // :)
enum struct ScopedBaselessEnum; // :)
enum struct ScopedBaselessEnum; // :)
ScopedBaselessEnum sbe;
//enum UnscopedBaseLessEnum; // :(
all of which is C++11 compliant.
The declarations of ube and sbe prove, however, that none of the
declarations here is a forward declaration, if foward declaration has the customary meaning
of declaration of an incomplete type. If UnscopedBasedEnum|ScopedBaselessEnum
was an incomplete type in these declarations then the declaration of ube|sbe would
would declare an object of incomplete type, and would not compile. Per C++11, the declarations
of UnscopedBasedEnum and ScopedBaselessEnum are opaque enum declarations, meaning
that no enumerator-list is present or implied. But they nevertheless declare complete
types: p 7.2.3
An opaque-enum-declaration is either a redeclaration of an enumeration in the current scope or a declaration
of a new enumeration. [ Note: An enumeration declared by an opaque-enum-declaration has fixed underlying
type and is a complete type. The list of enumerators can be provided in a later redeclaration with an enum-specifier.
—end note ]
What you are doing here is enum forward declaration. Some compilers (like VS) provide language extensions which enable this behaviour for pre-C++11 standard. You can verify this by disabling the language extensions in your project settings which will result in a compiler error. G++ does not have such extensions but it should compile your code with -std=c++11 after adding size specifiers or when using enum class instead.
Valid in Visual Studio with compiler extensions enabled
enum E;
enum E;
Valid in all compilers supporting C++11
enum class E;
enum class E;
// or
enum E : short;
enum E : short;
class Test
{
enum{};
...
};
Is this empty enum definition portable? Compiles in gcc and and msvc.
such an enum is specifically listed in clause 7 paragraph 3 of the C++ standard as
ill-formed. gcc does not accept it. there was a bug fix for this in gcc:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29018
According to the following snippet from the c++ standard we can deduce that it's indeed a valid statement:
7.2/1 Enumeration declarations (C++03)...
enum-specifier:
enum identifieropt { enumerator-listopt }
Note that both the identifier and the enumerator-list are optional, and therefor a statement as enum {} is valid (if you ask the standard).
But doesn't the standard also say that empty declarations are ill-formed?
Yes, and there is even an example of enum { }; in the below snippet from the standard.
7/3 Specifiers (C++03)
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 being 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]
Conclusion
The statement seems to be ill-formed after a careful look at the standard, though compilers are written by humans - and humans tend to make mistakes and sometimes overlook things.
TL;DR You should not use an empty declaration such as enum { };, even though it compiles
Motivated by the discussion
The grammar for C++ classes is defined as
class-key identifier *[opt]* base-clause *[opt]* (Italics are mine)
This to me means that the class name is option and we can have unnamed classes in C++.
So, is the following well-formed?
struct X{
struct{
int x;
int y;
};
};
int main(){}
VS: error C2467: illegal declaration
of anonymous 'struct'
Comeau online: error: declaration does
not declare anything
struct{
GCC(ideone): Compiles fine
Any thoughts?
No, it is not well-formed. You cannot derive the language syntax from these grammar statements alone. The extra requirements are given in the text of the standard also have to be taken into account. In this case that would be
7 Declarations
...
3 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 being 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.
The last sentence is the one that matters in this case
The "optional" part is only there to allow declarations like
struct { int x; } s;
typedef struct { int x, y; } Point;
The first one which declares a class type with no linkage and variable s of that type. Note that types with no linkage cannot be used to declare a variable with linkage, meaning that such declaration cannot be used in namespace scope.
Your example is ill-formed, but this would be legal
struct X {
struct {
int x;
int y;
} point;
};
Also, nameless class syntax is used to declare anonymous unions (although I'm a bit puzzled by the fact that 7/3 does not mention anonymous unions).
That code is actually valid in MSVC, you must have compiled in a restricted mode.
And while I would most likely never use them, they do allow for some interesting usage, like this:
X obj;
obj.x=1;
obj.y=2;
They're used for example in the LARGE_INTEGER class, only it's an union instead. This way you can avoid sub-objects when all you really want is one member to be splittable into smaller pieces.
The LARGE_INTEGER declaration as a visual example:
#if defined(MIDL_PASS)
typedef struct _LARGE_INTEGER {
#else // MIDL_PASS
typedef union _LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
};
struct {
DWORD LowPart;
LONG HighPart;
} u;
#endif //MIDL_PASS
LONGLONG QuadPart;
} LARGE_INTEGER;
As far as I know however, this isn't valid standard C++, it's only allowed as extensions in gcc and msvc.