I've been using static_assert
(and the variants before standardization) quite heavily. One use that I'm sure many of us have them put to is ensuring that the size of sensitive data structures remain as assumed across platforms and configurations. For example:
class SizeSensitiveClass
{
// ...
};
static_assert (sizeof(SizeSensitiveClass) == 18, "Check the size!");
Now, I've written a convenience macro to help with this particular use:
#define STATIC_ASSERT_SIZE(T, sz) (sizeof(T) == (sz), "Size of '" #T "' doesn't match the expected value.")
Used like this:
STATIC_ASSERT_SIZE (SizeSensitiveClass, 18);
Which produces this output: (at compile time, obviously, in form of compile error)
Size of 'SizeSensitiveClass' doesn't match the expected value.
This is OK and nice, but I was wondering whether I can extend the implementation of this macro (keeping the interface intact) to output the current size and the expected size of the data structure as well. Ideally, the output should look something like:
Size of 'SizeSensitiveClass' doesn't match the expected value (20 vs. 18).
Even the current size would be extremely convenient. Is this possible?
I'm using VC12 (Visual C++ 2013) and GCC 4.8.1. I'd appreciate any solutions/techniques/methods that would be portable to at least these two.
I should mention that I have tried the common "stringize" trick, but it doesn't work (as one would have expected it not to.) It just produces the literal string sizeof(T)
in the output.
I have a vague notion that this might be implemented using constexpr
s (to generate the message string) but I'm not familiar with them.
This might not be a solution in the sense you envision it, but it generates an error message which always contains the real size and the expected size close the error message from the static_assert
:
#include <type_traits>
template< typename Type, std::size_t ExpectedSize, std::size_t ActualSize = 0 >
struct validate_size : std::true_type
{
static_assert( ActualSize == ExpectedSize,
"actual size does not match expected size" );
};
template< typename Type, std::size_t ExpectedSize >
struct validate_size< Type, ExpectedSize, 0 >
: validate_size< Type, ExpectedSize, sizeof( Type ) >
{};
int main()
{
static_assert( validate_size< int, 4 >::value, "Oops" );
static_assert( validate_size< int, 5 >::value, "Oops2" );
}
The error message from GCC 4.8:
main.cpp: In instantiation of 'struct validate_size<int, 5ul, 4ul>':
main.cpp:10:8: required from 'struct validate_size<int, 5ul>'
main.cpp:15:43: required from here
main.cpp:6:5: error: static assertion failed: actual size does not match expected size
static_assert( ActualSize == ExpectedSize, "actual size does not match expected size" );
^
The message from Clang also contains the <int, 5ul, 4ul>
-part, check for VS yourself.
Update: And you can obviously keep your interface intact:
#define STATIC_ASSERT_SIZE(T, sz) static_assert(validate_size<T,sz>::value, "")