3

我一直在大量使用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。我很感激任何至少可以移植到这两个的解决方案/技术/方法。

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

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

4

3 回答 3

8

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

活生生的例子

更新:你显然可以保持你的界面完好无损:

#define STATIC_ASSERT_SIZE(T, sz) static_assert(validate_size<T,sz>::value, "")
于 2013-10-31T07:49:42.707 回答
2

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

18如果您传递的不是文字,而是另一个名称#define,那么您将需要双字符串化技巧,以便在sz对其进行字符串化之前进行宏扩展。

不幸的是,预处理器不知道 的值sizeof(T),并且static_assert必须采用字符串文字。所以我认为你不走运,尽管我可能会遗漏一些东西。

于 2013-10-31T01:41:13.780 回答
1

可以,请看c++模板编程。创建一个模板类,其中模板 para 是一个值为 size(T) 的整数。如果断言失败,则在类中生成编译器错误。编译器将输出类名,您可以从中取回大小 (T) 的值。

于 2013-10-31T02:28:36.300 回答