Как объединить статический assert с sizeof и stringify?

использование памяти очень важно в моем приложении. Поэтому у меня есть конкретные утверждения, которые проверяют размер памяти во время компиляции и дают 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) ")");

но вы не можете использовать оператор stringize (#) для функции вызов.

Я также пробовал добавлять двойной stringize трюк, как это:

#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).

есть ли способ stringify результат sizeof в static_assert?

3 ответов


Я бы использовал диспетчеризацию по шаблону функции для проверки:

#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!

отладочная информация находится в параметрах шаблона обратной трассировки.

Если это действительно лучше, вам придется решить, и это также зависит от компилятора. Он также позволяет скрыть ожидаемый размер с помощью карты шаблона, суммировать до максимального размера и других причудливых вещей.


в зависимости от вашего компилятора шаблоны могут помочь:

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"

Как вы обнаружили, проблема здесь (Также см. Это очень похожий вопрос):

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

это невозможно сделать, потому что stringification выполняется препроцессором, а sizeof вычисляется во время компиляции.