如何将static_assert与sizeof和stringify结合?

问题描述 投票:17回答:4

内存使用率在我的应用程序中非常关键。因此,我有一个明确的断言,即在编译时检查内存大小,如果大小与我们之前认为正确的大小不同,则提供static_assert。

我已经定义了这样的宏:

#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "!");

此宏使编写此代码非常容易:

CHECKMEM(Book,144);
CHECKMEM(Library,80);

问题是,当此static_assert关闭时,可能很难找出新的大小(例如,通过使用隐藏的编译器选项“ / d1 reportAllClassLayout”)。如果我可以包含实际大小,那会更加方便,因此,代替:

书号不正确!

它将显示

[大小不适合书籍! (预期为144,大小为152)

我试图写这样的东西:

#define CHECKMEM(mytype, size) static_assert((sizeof(objectType) == size)), "Size incorrect for " #mytype "! (expected" #size ", size is " #sizeof(mytype) ")");

但是您不能在函数调用上使用字符串化(#)运算符。

我还尝试添加双字符串化技巧,如下所示:

#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)) ")");

但不打印size is 152,而是打印size is sizeof(Book)

是否可以在static_assert中将sizeof的结果字符串化?

c++ visual-studio-2010 c++11 stringify static-assert
4个回答
19
投票

我将在功能模板上使用分派来进行检查:

#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;
}

结果:

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!

调试信息在回溯的模板参数中。

如果确实更好,则必须决定,而且还取决于编译器。它还使您可以通过模板映射隐藏预期的大小,以求出最大大小和其他奇特的东西。


4
投票

取决于您的编译器,模板可能会提供帮助:

template<int s, int t> struct check_size {
  static_assert(s == t, "wrong size");
};
check_size<2+2, 5> doubleplusungood;

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"

2
投票

正如您所发现的,问题出在这里(另请参见此very similar question):

#define CHECKMEM(mytype, size)  #sizeof(mytype)

不可能这样做,因为字符串化是由预处理程序完成的,并且sizeof是在编译期间求值的。


0
投票

如果您可以稍微修改结构的定义并且不介意某些丑陋的情况,那么这是另一种仅标头的解决方案。

template <int RealSize = 0, int ExpectedSize = 0>
struct _MyStruct {
    static_assert(RealSize == ExpectedSize, "size is invalid");

    int x;
};

typedef _MyStruct<sizeof(_MyStruct<>), 4> MyStruct;

clang输出:

prog.cpp:4:5: error: static_assert failed "size is invalid"
    static_assert(RealSize == ExpectedSize, "size is invalid");
    ^             ~~~~~~~~~~~~~~~~~~~~~~~~
prog.cpp:12:14: note: in instantiation of template class '_MyStruct<4, 8>' requested here
    MyStruct m;

这里的一个警告是,仅当您在某个地方实例化类型时才会进行检查-仅使用指针不会触发该错误,因此绝对不适合所有情况!

© www.soinside.com 2019 - 2024. All rights reserved.