Подтвердить что ты не робот

Как совместить static_assert с sizeof и строчить?

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

Я также попытался добавить трюк с двойной строкой, например:

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

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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"

Ответ 3

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

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

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