Как объединить статический 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 вычисляется во время компиляции.