Утверждение времени компиляции?
Есть ли способ, которым я могу утверждать, что во время компиляции равны два постоянных выражения?
например, я хочу, чтобы это вызывало ошибку времени компиляции
enum { foo=263, bar=264 }; SOME_EXPRESSION(foo,bar)
но я хочу, чтобы это не вызывало ошибку
- Почему автобоксирование делает некоторые вызовы неоднозначными на Java?
- Почему Java-код с внутренним classом генерирует третий файл SomeClass $ 1.class?
- Литералы номер компилятора C #
- Почему Java-переключатель на непрерывных ints работает быстрее с добавленными случаями?
- Каков размер пустой структуры в C?
enum { foo=263, bar=263 }; SOME_EXPRESSION(foo,bar)
edit: выше было упрощено. Моя ситуация больше похожа на
some_other_file_I_dont_control.h:
class X { public: enum { foo=263 }; }
my_file.h:
enum { bar=something+somethingelse }; // bar should equal X::foo SOME_EXPRESSION(X::foo, bar)
- Как создать АСТ с ANTLR4?
- Лучший уровень предупреждения компилятора для компиляторов C / C ++?
- Как компилятор C # обнаруживает типы COM?
- Зачем компилировать ошибку «Использование неназначенной локальной переменной»?
- Делегирование изменений поведения кеширования в Roslyn
- В чем разница между sjlj vs dwarf vs seh?
- Почему компилятор C # испускает инструкцию callvirt для вызова метода GetType ()?
- Что такое Haskell's Stream Fusion
См. static_assert
(только для C ++ 0x); если в более старой версии см . StaticAssert
Boost .
Да. Вы можете сделать это с помощью специализированных шаблонов типа bool, например:
// empty default template template struct StaticAssert {}; // template specialized on true template <> struct StaticAssert { static void assert() {} }; int f() { StaticAssert<1==1>::assert(); // compiles fine, assert() member found StaticAssert<1==2>::assert(); // compile failure, no assert() member for StaticAssert }
Код в основном из памяти, может потребоваться некоторые настройки.
Для другой версии статического утверждения, которую вы можете прославить, добавив лучшее имя, вы можете использовать:
// name must be a valid identifier #define STATIC_ASSERT( condition, name )\ typedef char assert_failed_ ## name [ (condition) ? 1 : -1 ];
И используйте как:
STATIC_ASSERT( x == y, constants_must_be_same );
Компилятор вызовет ошибку, аналогичную:
size of array 'assert_failed_constants_must_be_same' is negative
Это не похоже на то, что полезно, но оно будет указывать на точную строку assert, и через некоторое время вы начнете обрабатывать это сообщение об ошибке, поскольку статическое утверждение не прошло
Другой возможностью для Windows является C_ASSERT , которая определяется, если включена Windows.h.
вы можете определить свое собственное статическое утверждение, таким образом:
#include template class ClassStaticAssert; template <> class ClassStaticAssert{static const bool value = true;}; #define STATIC_ASSERT(e) (ClassStaticAssert()) int main() { STATIC_ASSERT(0); return 0; }
Подобно решению iammillind, которое, к сожалению, было полезно только во время выполнения:
template class VALUES { }; // specialization to provide safe passage for equal values template class VALUES { public: static void MY_VALUES_ARE_EQUAL() {} }; #define ASSERT_EQUALITY(a, b) \ { \ typedef VALUES COMPILE_TIME_ASSERTION; \ COMPILE_TIME_ASSERTION::VALUES_ARE_EQUAL(); \ } int main() { ASSERT_EQUALITY(1, 1); // compiles just fine ASSERT_EQUALITY(1, 2); // ERROR! // . . . }
Самое приятное в этом заключается в том, что он обеспечивает хорошее сообщение компилятора. Мой компилятор говорит мне следующее:
‘VALUES_ARE_EQUAL’ не является членом ‘COMPILE_TIME_ASSERTION {aka VALUES <1, 2>}’
Вам не нужен typedef. Без:
‘VALUES_ARE_EQUAL’ не является членом ‘VALUES <1, 2>‘
Конечно, существует множество других способов генерации полезных сообщений. Для хихиканья:
// these give use some tips in the compiler warnings class COMPILE_TIME_EQUALITY_ASSERTION {} compiler_message; class EQUAL_VALUES_ONLY_PLEASE {}; template class VALUES { public: static void AreEqual(EQUAL_VALUES_ONLY_PLEASE) {} }; template class VALUES { public: static void AreEqual(COMPILE_TIME_EQUALITY_ASSERTION) {} }; #define ASSERT_EQUALITY(a, b) \ { \ VALUES::AreEqual(compiler_message); \ } int main() { ASSERT_EQUALITY(1, 1) // a-okay ASSERT_EQUALITY(1, 2) // ERROR! }
Я получаю следующие compiler errors:
no matching function for call to: 'VALUES<1,2>::AreEqual(COMPILE_TIME_EQUALITY_ASSERTION&)' candidate is: static void VALUES<\A, B>::AreEqual(EQUAL_VALUES_ONLY_PLEASE) [with int A = 1, int B = 2]
комбинации статических функций-членов / конструкторов / назначения полей / конфиденциальности и спецификаций шаблонов могут дать разные результаты, возможно, более подходящие для вашей ситуации.
Существует также трюк с использованием оператора switch (..)
. Вид старого стиля. Строка ввода foo == bar должна быть оценена во время компиляции, и если она окажется ложной, оператор switch вызовет ошибку. Компилятор также уменьшит его до «ничего».
{ bool x=false; switch (x) { case foo == bar: break; case false: // Compile time test that foo == bar break; }
template inline void static_assert_equal() { typedef char enum_values_must_be_equal[a == b ? 1 : -1]; (void) sizeof(enum_values_must_be_equal); } int main() { enum { foo = 1, bar = 2, fum = foo }; static_assert_equal(); // compiles ok static_assert_equal(); // fails at compile time return 0; }
Это происходит из идиомы checked_delete
.
Вы можете сделать магию препроцессора, например
#define FOO_VALUE 263 #define BAR_VALUE 264 enum {foo=FOO_VALUE, bar=BAR_VALUE} #if !(FOO_VALUE == BAR_VALUE) #error "Not equal" #endif
Я бы выбрал один из доступных static_asserts.
- повышение :: static_assert
- C ++ 0x static_assert
Но только потому, что я никогда не пробовал, прежде чем написал это:
enum { foo=263, bar=264 }; template struct CompileAssert { bool assert() {} }; template<> struct CompileAssert {}; // fail on false. int main() { CompileAssert().assert(); // Now I have seen Chad above I like his static CompileAssert ().assert(); // method better than using a normal method. } // But I tried zero length arrays first did // not seem to work
Я предлагаю взглянуть на механизм статического утверждения библиотеки Eigen:
template struct Check { enum { value = false }; }; template struct Check { enum { value = true }; };
Я привел пример int
. Вы можете изменить его в соответствии с вашими потребностями. Вот демо . Применение:
Check::value