Как совместить 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?
Ответы
Ответ 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 оценивается во время компиляции.