2011-07-27 15 views
6

¿Es legal la siguiente según el estándar de C++? (Si la respuesta es diferente de la norma a norma, me gustaría saber que, también.)¿Definir un no-op de nivel superior en C++?

#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. 

El objetivo es definir una macro que pueda invocar en la línea de nivel superior y seguir con un punto y coma , tal que no tiene ningún efecto. Estoy bastante seguro de que los puntos y comas parciales en el nivel superior no están permitidos (GCC se queja de ellos, de todos modos), así que simplemente definir una macro vacía no funciona.

Declarar una estructura anónima vacía no funciona porque necesita un nombre, y no quiero contaminar el espacio de nombres.

¿Hace una declaración enum vacía vacía (enum { }) hacer el truco? Funciona en todos los compiladores que he probado, pero, por supuesto, eso no es lo mismo que estar permitido por la especificación.

Cualquier otra idea/comentario de bienvenida. Bueno, cualquier cosa que no sea "descartar ese compilador". Créame, me encantaría.

+6

¿Por qué debe seguir la macro llamada con un punto y coma? ¿No sería trivial resolver esto si no hicieras eso? –

+1

@Greg: preferencia personal. Estoy acostumbrado a invocar macros como 'DO_STUFF (x, y);' dentro de una función, y sé cómo escribir un no-operativo como ese. Creo que 'USING_NAMESPACE_STD' es un buen nombre para esto, y creo que poner un punto y coma al final parece natural, así que eso es lo que quiero. Tengo curiosidad de saber si es posible en el idioma definido por la especificación. – Nemo

+1

Estoy de acuerdo con preferir el punto y coma al final. Hay momentos en los que tiene que usar macros de declaración que no pueden seguirse con un punto y coma, pero si puede evitar eso, debería hacerlo. –

Respuesta

6

Al mirar el último borrador público de C++ 0x, parece que los puntos y coma en el nivel superior están permitidos e ignorados.

La gramática trata una translation-unit como una secuencia de declaration s, y entre los diversos tipos de declaraciones hay una empty-declaration que es sólo un punto y coma simple.

solución pragmática: teniendo en cuenta que su constante VERY_OLD_COMPILER sugiere que todo el asunto es ser parte de una solución para un compilador de más edad, que acababa de recoger una solución que funciona con este compilador, ya sea o no normalizados .

+0

De hecho, a los CCG más nuevos no parece importarles el punto y coma. Además, es bueno señalar que solo necesita trabajar en un compilador. Gracias por investigar sobre la especificación. – Nemo

2

Comeau dice que 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". 

Usted puede utilizar

#define USING_NAMESPACE_STD struct very_long_name_that_i_hope_doesnt_collide_because_if_it_does_oh_noes 
+0

+1 para obtener buena información, pero es más probable que acepte una respuesta si cita el capítulo y el versículo de una especificación. – Nemo

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; 

Editar: Esto debería funcionar también:

#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; 
+0

Como mencioné, eso no funciona porque el punto y coma es ilegal. – Nemo

+0

Lo siento, mi gcc no se quejó de eso. Pruebe la solución typedef. –

+0

'int main();' no es bueno C++. A diferencia de C, donde significa "argumentos no especificados", en C++ eso significa "sin argumentos", lo que puede causar un error. –

4
#define USING_NAMESPACE_STD static int dummy##__LINE__ 
+0

¿Es lamentable el pobre programador que decide nombrar una función "dummy13"? :-) Tal vez sería mejor elegir 80 caracteres aleatorios ... ¿Realmente no hay forma de hacerlo sin contaminar el espacio de nombres? – Nemo

0

Lo siento, olvidé que necesitabas hacerlo en el nivel superior.

¿Qué tal

extern int _; 

? No sé qué efectos secundarios indeseables tendría, aunque no puedo pensar en ninguno.

4

una enumeración vacía es de hecho ilegal de acuerdo a C++ 03:

7/3 Declaraciones:

En una simple declaración, el declarador-init-lista opcional se puede omitir solamente cuando se declara una clase (cláusula 9) o enumeración (7.2), es decir, cuando el especificador de declinación-seq contiene un especificador de clase, un especificador de tipo elaborado con una clave de clase (9.1) o un especificador de enumeración.En estos casos y siempre que un especificador de clase o especificador enum esté presente en decl-specifier-seq, los identificadores en estos especificadores se encuentran entre los nombres declarados por la declaración (como nombres de clase, nombres enum o enumeradores, dependiendo de la sintaxis). En tales casos, y a excepción de la declaración de un campo de bit sin nombre (9.6), el decl-specifier-seq introducirá uno o más nombres en el programa, o redeclarará un nombre introducido por una declaración previa.

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

Así que estoy de acuerdo con MSN's answer para declarar un maniquí enum, struct declaración adelantada, o typedef declaración con un nombre que es, obviamente, no va a entrar en conflicto con cualquier cosa (lanzar un GUID allí por si acaso). Lo bueno de estas cosas es que puedes hacer que la declaración aparezca más de una vez, y siempre que sea la misma que antes no hay problema.

+0

Lo siento, solo puedo aceptar una respuesta. (Eso es lo que obtengo por hacer dos preguntas). – Nemo

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. 
Cuestiones relacionadas