c++ - ¿Cómo combinar static_assert con sizeof y stringificar?
visual-studio-2010 c++11 (3)
Como descubrió, el problema está aquí (vea también esta pregunta muy similar ):
#define CHECKMEM(mytype, size) #sizeof(mytype)
No es posible hacerlo, ya que la preprocesación se realiza mediante la cadena de caracteres y se evalúa sizeof durante la compilación.
El uso de la memoria es bastante crítico en mi aplicación. Por lo tanto, tengo afirmaciones específicas que verifican el tamaño de la memoria en el momento de la compilación y le doy una static_assert si el tamaño es diferente de lo que antes considerábamos correcto.
He definido una macro como esta:
#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "!");
Esta macro hace que sea muy fácil escribir esto:
CHECKMEM(Book,144);
CHECKMEM(Library,80);
El problema es que cuando se desactiva esta static_assert, puede ser bastante difícil averiguar cuál debería ser el nuevo tamaño (por ejemplo, utilizando la opción de compilador oculto "/ d1 reportAllClassLayout"). Sería mucho más práctico si pudiera incluir el tamaño real, así que en lugar de:
Tamaño incorrecto para el libro!
Se mostraría
Tamaño incorrecto para el libro! (Se espera 144, el tamaño es 152)
Intenté escribir algo como esto:
#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "! (expected" #size ", size is " #sizeof(mytype) ")");
Pero no puede usar el operador de ajuste de cadena (#) en una llamada de función.
También intenté agregar el truco de doble cadena, como este:
#define STR1(x) #x
#define STR2(x) STR1(x)
#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "! (expected" #size ", size is " STR2(sizeof(mytype)) ")");
Pero en lugar de imprimir, el size is 152
, imprime el size is sizeof(Book)
.
¿Hay alguna forma de restringir el resultado de sizeof en un static_assert?
Dependiendo de tu compilador, las plantillas pueden ayudarte:
template<int s, int t> struct check_size {
static_assert(s == t, "wrong size");
};
check_size<2+2, 5> doubleplusungood;
salidas gcc:
prog.cpp: In instantiation of ''check_size<4, 5>'':
prog.cpp:5:20: instantiated from here
prog.cpp:2:3: error: static assertion failed: "wrong size"
Usaría el envío en una plantilla de función para realizar la comprobación:
#include <cstddef>
template <typename ToCheck, std::size_t ExpectedSize, std::size_t RealSize = sizeof(ToCheck)>
void check_size() {
static_assert(ExpectedSize == RealSize, "Size is off!");
}
struct foo
{
char bla[16];
};
int main()
{
check_size<foo, 8>();
return 0;
}
Resultados en:
In instantiation of ‘void check_size() [with ToCheck = foo; long unsigned int ExpectedSize = 8ul; long unsigned int RealSize = 16ul]’:
bla.cpp:15:22: required from here
bla.cpp:5:1: error: static assertion failed: Size is off!
La información de depuración se encuentra en los parámetros de plantilla de la traza inversa.
Si esto es realmente mejor, tendrá que decidir y también depende del compilador. También le permite ocultar el tamaño esperado con un mapa de plantilla, para sumar un tamaño máximo y otras cosas elegantes.