2010-05-25 14 views
5

Las afirmaciones estáticas son muy prácticas para verificar cosas en tiempo de compilación. Un simple modismo afirman estática se ve así:static assert for const variables?

template<bool> struct StaticAssert; 
template<> struct StaticAssert<true> {}; 

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0) 

Esto es bueno para cosas como

STATIC_ASSERT(sizeof(float) == 4) 

y:

#define THIS_LIMIT (1000) 
... 
STATIC_ASSERT(THIS_LIMIT > OTHER_LIMIT); 

Pero el uso de #define no es el camino "C++" de definir constantes. C++ tendría que utiliza un espacio de nombres en el anonimato:

namespace { 
    const int THIS_LIMIT = 1000; 
} 

o incluso:

static const int THIS_LIMIT = 1000; 

El problema con esto es que con un const int no se puede utilizar STATIC_ASSERT() y hay que recurrir a un tiempo de ejecución comprobar qué es tonto.

¿Hay alguna manera de resolver esto correctamente en C++ actual?
Creo que he leído C++ 0x tiene cierta facilidad para hacer esto ...


EDITAR

Ok por lo que este

static const int THIS_LIMIT = 1000; 
... 
STATIC_ASSERT(THIS_LIMIT > 0); 

compila bien
Pero esto:

static const float THIS_LIMIT = 1000.0f; 
... 
STATIC_ASSERT(THIS_LIMIT > 0.0f); 

no.
(en Visual Studio 2008)

¿Cómo?

+0

¿Por qué está utilizando NIH static assert, en lugar de BOOST_STATIC_ASSERT? http://www.boost.org/doc/libs/1_43_0/doc/html/boost_staticassert.html –

+0

No puedo usar boost (aún) por alguna tonta razón corporativa – shoosh

+1

¿Qué le hace pensar que no puede usar constantes integrales en este caso? Lo anterior debería funcionar bien. –

Respuesta

10

Por qué, todavía se puede afirmar estático con const int:

#define static_assert(e) extern char (*ct_assert(void)) [sizeof(char[1 - 2*!(e)])] 
static_assert(THIS_LIMIT > OTHER_LIMIT) 

Además, use boost!

BOOST_STATIC_ASSERT(THIS_LIMIT > OTHER_LIMIT) 

... usted obtendrá una gran cantidad mensajes de error más agradables ...

+0

Bueno, hay una lección para mí. no digas que algo no es posible antes de intentarlo ... – shoosh

+0

Todavía me pregunto qué problema se supone que solucionará? –

+0

@shoosh: Tu código original debería compilarse bien. Ver [mi respuesta] (http://stackoverflow.com/questions/2902917/2903013#2903013). – sbi

1

Tal vez estás confundiendo el comportamiento de C++ 's con C, donde const int no representa una verdadera constante en tiempo de compilación. O tal vez su compilador C++ está roto. Si es realmente el último, use enum en su lugar.

+0

tienes +1, tengo -1 para la misma solución =/ –

+0

@Viktor Sehr: Para ser justos, mi respuesta proporciona una explicación más importante que la tuya, y el uso de 'enum' no * es * necesario en C++ para este caso. – jamesdlin

+0

@ViktorSehr: Este lugar no se trata de tirar "soluciones" en trozos de código como si fueran trozos de carne; se trata de escribir _ respuestas_ para explicar, enseñar e informar. A menudo, las buenas respuestas incluyen ilustraciones de código, pero eso no significa que una respuesta que consista en una sola fuente de código sea buena. De hecho, es raro que ese sea el caso. –

1

Este:

namespace { 
    const int THIS_LIMIT = 1000; 
} 

template<bool> struct StaticAssert; 
template<> struct StaticAssert<true> {}; 

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0) 

int main() 
{ 
    STATIC_ASSERT(THIS_LIMIT > 5); 

    return (0); 
} 

compila bien con VC y Comeau.

0

enum{THIS_LIMIT = 1000};

+0

¿Por qué el voto de -1? –

+1

No te he desvalorizado, pero esta no es una respuesta a la pregunta. Es una solución válida y es un código válido, pero proporcionó cero descripción, cero explicación y cero análisis de (a) lo que hace, (b) cómo difiere del código de OP y (c) por qué debería ser utilizado (y , de hecho, _no_ necesita ser). En consecuencia, parece un poco flojo, y es probable que sea por eso que se votó negativamente. De hecho, ahora que lo pienso, voy a rechazarlo también por esa razón. Lo siento. –

+0

No se preocupe, creo que proporcionó una buena explicación :) –

4

static_assert es una característica del compilador en C++ 0x así que mientras usted tiene un compilador relativamente hasta a la fecha se puede usar eso.Tenga cuidado con hacer #define static_assert(x) ..., porque es una palabra clave real en C++ 0x por lo que estaría ocultando permanentemente la característica del compilador. Además, C++ 0x static_assert toma dos parámetros (por ejemplo, static_assert(sizeof(int) == 4, "Expecting int to be 4 bytes")), por lo que podría causar problemas tratando de cambiar en el futuro si usa ese #define.

2

Parece que estás realmente preguntan por qué el siguiente es el caso (y puedo confirmar que tanto en GCC 4.3.4 y Visual C++ 2008 Express):

template<bool> struct StaticAssert; 
template<> struct StaticAssert<true> {}; 

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0) 


static const int AN_INT = 1000; 
static const float A_FLOAT = 1000.0f; 

int main() 
{ 
    STATIC_ASSERT(AN_INT > 0);  // OK 
    STATIC_ASSERT(A_FLOAT > 0.0f); // Error: A_FLOAT may not appear in a constant expression 
} 

Hay una serie de restricciones en el uso de valores de punto flotante estáticamente. Tenga en cuenta, por ejemplo, que no puede pasarlos como argumentos de plantilla. Esto se debe a:

[C++11: 5.19/2]:A condicional-expresión es una expresión constante de núcleo a menos que se trata de uno de los siguientes como una subexpresión potencialmente evaluado (3.2), pero subexpresiones de lógica Y (5,14), lógica Las operaciones OR (5.15) y las condicionales (5.16) que no se evalúan no se consideran [Nota: Un operador sobrecargado invoca una función . -end nota] :

  • [..]
  • un lvalue-a-rvalue de conversión (4,1) a menos que se aplica a
    • un glvalue de integral o enumeración tipo que hace referencia a un objeto const no volátil con una inicialización precedente, inicializado con una expresión constante, o
    • un glvalue de tipo literal que se refiere a un objeto no volátil definido con constexpr, o que se refiere a un subobjeto de dicho objeto, o
    • un glvalue de tipo literal que hace referencia a un objeto temporal no volátil cuya duración no ha finalizado, inicializado con una constante expresión;
  • [..]

(es decir, se permite sólo tipos integrales y de enumeración;. No hay tipos de coma flotante)

En cuanto a la razón para esta regla, yo No estoy del todo seguro, pero el siguiente tipo de razonamiento puede tener algo que ver con eso:

[C++11: 5.19/4]: [..] Dado que esta Norma Internacional no impone restricciones a la precisión de las operaciones de coma flotante, no se especifica si la evaluación de una expresión de coma flotante durante la traducción arroja el mismo resultado que la evaluación de la misma expresión (o las mismas operaciones en los mismos valores) durante la ejecución del programa. [..]

Cuestiones relacionadas