对于对象大小的`static_assert`更好的消息

时间:2013-10-31 01:36:15

标签: c++ c++11 c-preprocessor static-assert

我一直在使用static_assert(以及标准化之前的变体)。我相信我们很多人都会使用它的一个用途是确保敏感数据结构的大小保持在平台和配置之间。例如:

class SizeSensitiveClass
{
    // ...
};

static_assert (sizeof(SizeSensitiveClass) == 18, "Check the size!");

现在,我已经编写了一个方便宏来帮助实现这一特定用途:

#define STATIC_ASSERT_SIZE(T, sz)  (sizeof(T) == (sz), "Size of '" #T "' doesn't match the expected value.")

像这样使用:

STATIC_ASSERT_SIZE (SizeSensitiveClass, 18);

产生此输出:(在编译时,显然,以编译错误的形式)

  

'SizeSensitiveClass'的大小与预期值不匹配。

这很好,但是我想知道我是否可以扩展此宏的实现(保持接口完整)以输出当前大小预期大小也是数据结构。理想情况下,输出应该类似于:

  

'SizeSensitiveClass'的大小与预期值(20对18)不匹配。

即使是当前尺寸也会非常方便。这可能吗?

我正在使用VC12(Visual C ++ 2013)和GCC 4.8.1。我很感激任何可以移植到至少这两个的解决方案/技术/方法。

我应该提到我已经尝试过常见的“stringize”技巧,但它不起作用(正如人们所预料的那样。)它只是在输出中生成文字字符串sizeof(T)。 / p>

我有一个模糊的概念,即可以使用constexpr来实现(生成消息字符串),但我不熟悉它们。

3 个答案:

答案 0 :(得分:6)

这可能不是您设想的解决方案,但它会生成一条错误消息,该消息始终包含实际大小和预期大小,并关闭来自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" );
}

来自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" );
     ^

来自Clang的消息还包含<int, 5ul, 4ul> - 部分,请自行检查VS.

Live example

更新:你显然可以保持你的界面完整:

#define STATIC_ASSERT_SIZE(T, sz) static_assert(validate_size<T,sz>::value, "")

答案 1 :(得分:2)

Stringize应该适用于预期的大小。在#sz中使用时,"18"会扩展为STATIC_ASSERT_SIZE(或您传递的任何数字文字)。

如果您不是文字18,而是传递另一个#define的名称,那么您需要double-stringize trick才能在对其进行字符串化之前对其进行宏扩展sz

不幸的是,预处理器不知道sizeof(T)的值,而static_assert必须采用字符串文字。所以我觉得你运气不好,虽然我可能会遗漏一些东西。

答案 2 :(得分:1)

你可以,请参阅c ++模板编程。创建一个模板类,其中模板para是一个值为size(T)的整数。如果断言失败,则将编译器错误输入到类中。编译器将输出类名,您可以从中返回size(T)的值。