Преамбула:
switch(nValue)
{
case X:
...
case Y:
...
default:
ASSERT_FOR_DEFAULT(nValue);
}
ASSERT_FOR_DEFAULT
является макросом, который отображает (пользовательское) диалоговое окно подтверждения, чтобы сообщить о попадании в «default-case». Да, этот макрос предназначен для подтверждения времени выполнения, а не для утверждения времени компиляции. Но мне просто нужно, чтобы любое постоянное значение (время компиляции) не могло быть передано этому макросу.
Проблема:
Следует потерпеть поражение при компиляции:
ASSERT_FOR_DEFAULT(5);
Да, программист может использовать его где угодно, а не только в default
случай switch-case
, Он также может использовать любое выражение, которое не используется в switch
, Но это не проблема. Просто нужно, чтобы в этот макрос передавалась только непостоянная величина.
Для этого макроса не написано ничего важного, просто предположим, что это ASSERT
/assert
,
Я пробовал с шаблонами (использовал их другие SFINAE / static-asserts!), Массивы (как strcpy_s
), собственная структура, имеющая YES
, NO
типы, а что нет. Но не смог найти решение!
Я использую VC2008. Я в курсе static_assert
, decltype
и т.д., но не может использовать C ++ 0x.
РЕДАКТИРОВАТЬ (решение):
#define STATIC_ASSERT(expr) {int array[!!(expr)]; expr;}
template <class T>
bool noConstAllowed(T&);
int noConstAllowed(...);
#define ASSERT_FOR_DEFAULT_VALUE(val) \
{ \
STATIC_ASSERT(sizeof(noConstAllowed(val))==sizeof(bool)); \
}
int main()
{
int test=10;
ASSERT_FOR_DEFAULT_VALUE(test);
ASSERT_FOR_DEFAULT_VALUE(2);
ASSERT_FOR_DEFAULT_VALUE(test+2); //FAILS, but okay for me!
}
Спасибо Арне Мерц за это прекрасное предложение. Я вывел решение из этого.
noConstAllowed
перегружен для всех T&
типы, и если константное значение передается, вызывается другая перегрузка. Оба имеют разные типы возвращаемых значений, и, следовательно, сверяются с размером. Шаблонная версия возвращает bool
, который удовлетворяет утверждению для любой передаваемой переменной и завершается неудачей для любой константы или выражения (поскольку возвращаемый тип будет int
).
Вы можете переопределить макрос так, чтобы он принимал адрес параметра — что не должно работать для литералов. Однако это не помешает вам передать постоянную переменную, например,
const static int FIVE = 5;
ASSERT_FOR_DEFAULT(FIVE); // still works.
Запрещать все виды констант, передаваемых в ваш макрос, вызывают функцию, которая принимает параметр по неконстантной ссылке:
template <class T> void noConstAllowed(T&){};
#define ASSERT_FOR_DEFAULT_VALUE(val) \
{ \
(void*)&(val); /* no literals*/ \
noConstAllowed(val); /* no constants at all */ \
switchHitDefaultDialog(val, __FILE__, __LINE__); \
}
Я полагаю, вы используете что-то вроде ФАЙЛ или другие позиционные макросы, или вы бы сделали это функцией. Вам нужно использовать только одну из двух строк.
Других решений пока нет …