Pregunta

¿Podría dar un ejemplo donde static_assert (...) 'C ++ 0x' resolvería el problema en la mano con elegancia?

Estoy familiarizado con el tiempo de ejecución afirmar (...) . ¿Cuándo debería preferir static_assert (...) sobre afirmar (...) ?

Además, en boost hay algo llamado BOOST_STATIC_ASSERT , ¿es lo mismo que static_assert (...) ?

¿Fue útil?

Solución

Fuera de mi cabeza ...

#include "SomeLibrary.h"

static_assert(SomeLibrary::Version > 2, 
         "Old versions of SomeLibrary are missing the foo functionality.  Cannot proceed!");

class UsingSomeLibrary {
   // ...
};

Suponiendo que SomeLibrary :: Version se declara como una constante estática, en lugar de ser #define d (como cabría esperar en una biblioteca C ++).

Contraste con tener que compilar SomeLibrary y su código, vincular todo y ejecutar el ejecutable solo luego para descubrir que pasó 30 minutos compilando una versión incompatible de SomeLibrary .

@Arak, en respuesta a tu comentario: sí, puedes tener static_assert simplemente sentado donde sea, por lo que parece:

class Foo
{
    public: 
        static const int bar = 3;
};

static_assert(Foo::bar > 4, "Foo::bar is too small :(");

int main()
{ 
    return Foo::bar;
}
$ g++ --std=c++0x a.cpp
a.cpp:7: error: static assertion failed: "Foo::bar is too small :("

Otros consejos

La aserción estática se utiliza para hacer aserciones en tiempo de compilación. Cuando la aserción estática falla, el programa simplemente no se compila. Esto es útil en diferentes situaciones, como, por ejemplo, si implementa alguna funcionalidad por código que depende críticamente de que el objeto unsigned int tenga exactamente 32 bits. Puede poner una afirmación estática como esta

static_assert(sizeof(unsigned int) * CHAR_BIT == 32);

en su código. En otra plataforma, con el tipo unsigned int de diferente tamaño, la compilación fallará, lo que llamará la atención del desarrollador sobre la parte problemática del código y le aconsejará que lo vuelva a implementar o volver a inspeccionar.

Para otro ejemplo, es posible que desee pasar algún valor integral como un puntero void * a una función (un truco, pero útil a veces) y desea asegurarse de que el valor integral será encajar en el puntero

int i;

static_assert(sizeof(void *) >= sizeof i);
foo((void *) i);

Es posible que desee utilizar ese tipo de char firmado

static_assert(CHAR_MIN < 0);

o esa división integral con valores negativos se redondea hacia cero

static_assert(-5 / 2 == -2);

Y así sucesivamente.

Las aserciones de tiempo de ejecución en muchos casos se pueden usar en lugar de las aserciones estáticas, pero las aserciones de tiempo de ejecución solo funcionan en tiempo de ejecución y solo cuando el control pasa sobre la aserción. Por esta razón, una afirmación de tiempo de ejecución fallida puede permanecer inactiva, sin ser detectada por largos períodos de tiempo.

Por supuesto, la expresión en aserción estática tiene que ser una constante en tiempo de compilación. No puede ser un valor de tiempo de ejecución. Para los valores de tiempo de ejecución no tiene otra opción que usar el afirmar .

Lo uso para asegurarme de que mis suposiciones sobre el comportamiento del compilador, los encabezados, las bibliotecas e incluso mi propio código son correctos. Por ejemplo, aquí verifico que la estructura se ha empaquetado correctamente al tamaño esperado.

struct LogicalBlockAddress
{
#pragma pack(push, 1)
    Uint32 logicalBlockNumber;
    Uint16 partitionReferenceNumber;
#pragma pack(pop)
};
BOOST_STATIC_ASSERT(sizeof(LogicalBlockAddress) == 6);

En una clase envolviendo stdio.h ' fseek () , he tomado algunos atajos con enum Origin y verifico que esos atajos alinearse con las constantes definidas por stdio.h

uint64_t BasicFile::seek(int64_t offset, enum Origin origin)
{
    BOOST_STATIC_ASSERT(SEEK_SET == Origin::SET);

Debería preferir static_assert sobre afirmar cuando el comportamiento se define en tiempo de compilación, y no en tiempo de ejecución, como los ejemplos que he dado anteriormente. Un ejemplo donde esto es no el caso incluiría la verificación de parámetros y código de retorno.

BOOST_STATIC_ASSERT es una macro anterior a C ++ 0x que genera código ilegal si no se cumple la condición. Las intenciones son las mismas, aunque static_assert está estandarizado y puede proporcionar mejores diagnósticos del compilador.

BOOST_STATIC_ASSERT es un contenedor multiplataforma para la funcionalidad static_assert .

Actualmente estoy usando static_assert para hacer cumplir " Conceptos " en una clase.

ejemplo:

template <typename T, typename U>
struct Type
{
  BOOST_STATIC_ASSERT(boost::is_base_of<T, Interface>::value);
  BOOST_STATIC_ASSERT(std::numeric_limits<U>::is_integer);
  /* ... more code ... */
};

Esto provocará un error de tiempo de compilación si alguna de las condiciones anteriores no se cumple.

Un uso de static_assert podría ser garantizar que una estructura (que es una interfaz con el mundo exterior, como una red o un archivo) tenga exactamente el tamaño que espera. Esto detectaría casos en los que alguien agrega o modifica un miembro de la estructura sin darse cuenta de las consecuencias. El static_assert lo recogería y alertaría al usuario.

En ausencia de conceptos, se puede usar static_assert para una verificación de tipo de tiempo de compilación simple y legible, por ejemplo, en plantillas:

template <class T>
void MyFunc(T value)
{
static_assert(std::is_base_of<MyBase, T>::value, 
              "T must be derived from MyBase");

// ...
}

Esto no responde directamente a la pregunta original, pero hace un estudio interesante sobre cómo hacer cumplir estas comprobaciones de tiempo de compilación antes de C ++ 11.

Capítulo 2 (Sección 2.1) de Modern C ++ Design de Andrei Alexanderscu implementa esto idea de afirmaciones en tiempo de compilación como esta

template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};

#define STATIC_CHECK(expr, msg) \
{ CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } 

Compare la macro STATIC_CHECK () y static_assert ()

STATIC_CHECK(0, COMPILATION_FAILED);
static_assert(0, "compilation failed");
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top