Memory usage is quite critical in my application. Therefore I have specific asserts that check for the memory size at compile time and give a static_assert if the size is different from what we considered correct before.
I have defined a macro like this:
#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "!");
This macro makes it very easy to write this:
CHECKMEM(Book,144);
CHECKMEM(Library,80);
The problem is that when this static_assert goes off, it might be quite difficult to find out what the new size should be (e.g. by using the hidden compiler option "/d1 reportAllClassLayout"). It would be much handier if I could include the actual size, so instead of:
Size incorrect for Book!
It would show
Size incorrect for Book! (expected 144, size is 152)
I tried writing something like this:
#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "! (expected" #size ", size is " #sizeof(mytype) ")");
But you can't use the stringize (#) operator on a function call.
I also tried adding the double-stringize trick, like this:
#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)) ")");
But instead of printing size is 152
it prints size is sizeof(Book)
.
Is there a way to stringify the result of sizeof in a static_assert?
I'd use dispatching on a function template to do the checking:
#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;
}
Results in:
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!
The debugging information is in the template parameters of the back-trace.
If this is truly better, you will have to decide and it also depends on the compiler. It also enables you to hide the expected size with a template map, to sum up to a max size and other fancy things.
Depending on your compiler, templates may be able to help:
template<int s, int t> struct check_size {
static_assert(s == t, "wrong size");
};
check_size<2+2, 5> doubleplusungood;
gcc outputs:
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"
As you discovered, the problem is here (also see this very similar question) :
#define CHECKMEM(mytype, size) #sizeof(mytype)
It is not possible to do, because the stringification is done by the preprocessor, and sizeof is evaluated during the compilation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With