Утверждение времени компиляции?

Есть ли способ, которым я могу утверждать, что во время компиляции равны два постоянных выражения?

например, я хочу, чтобы это вызывало ошибку времени компиляции

enum { foo=263, bar=264 }; SOME_EXPRESSION(foo,bar) 

но я хочу, чтобы это не вызывало ошибку

 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) 

См. 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:

http://eigen.tuxfamily.org/dox/StaticAssert_8h_source.html

 template struct Check { enum { value = false }; }; template struct Check { enum { value = true }; }; 

Я привел пример int . Вы можете изменить его в соответствии с вашими потребностями. Вот демо . Применение:

 Check::value 
  • Какова цель (-ы) встроенного?
  • Монокомпилятор как услуга (MCS)
  • shared_ptr: ужасная скорость
  • Почему autoboxing не отменяет varargs при использовании перегрузки методов в Java 7?
  • Какие функции C99 доступны в компиляторе MS Visual Studio?
  • Почему происходит отключение функции не-void без возврата значения, не приводящего к ошибке компилятора?
  • Целевой цикл C #import
  • Сведения о создании шаблона компиляторов GCC и MS
  • Есть ли способ установить gcc в OSX без установки Xcode?
  • Почему macros препроцессора злые и какие альтернативы?
  • Различия между компиляцией Just in Time и заменой стека
  • Давайте будем гением компьютера.