Утверждение времени компиляции? - PullRequest
33 голосов
/ 20 июля 2011

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

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

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

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

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

edit: theвыше было упрощено.Моя ситуация больше похожа на

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)

Ответы [ 12 ]

34 голосов
/ 20 июля 2011

Да.Вы можете сделать это с помощью шаблонов специализаций типа bool, например:

// empty default template
template <bool b>
struct StaticAssert {};

// template specialized on true
template <>
struct StaticAssert<true>
{
    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<false>
}

Код в основном из памяти, может потребоваться некоторые настройки.

33 голосов
/ 20 июля 2011

См. static_assert (только C ++ 0x);если на более старой версии, см. Boost's StaticAssert.

22 голосов
/ 20 июля 2011

Для другой версии статического утверждения, которую вы можете прославить, добавив более подходящее имя, вы можете использовать:

// 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

Что не кажется полезным, но оно будет указывать на точную строку утверждения, и через некоторое время вы начнете обрабатывать это сообщение об ошибке как статическое завершение не удалось

6 голосов
/ 04 января 2013

Другая возможность для Windows - C_ASSERT , которая определяется, если включен Windows.h.

3 голосов
/ 18 марта 2015

Существует также хитрость в использовании оператора switch (..). Вид старого стиля, хотя. Запись в регистре foo == bar должна быть оценена по времени компиляции, и если она окажется ложной, оператор switch вызовет ошибку Компилятор также уменьшит его до «ничего».

{ 
  bool x=false; 
  switch (x) {
  case foo == bar:
    break;
  case false:
    // Compile time test that foo == bar
    break;
}
2 голосов
/ 02 октября 2016

вы можете определить собственное статическое утверждение следующим образом:

#include <iostream>
template <bool b> class ClassStaticAssert;
template <>
class ClassStaticAssert<true>{static const bool value = true;};
#define STATIC_ASSERT(e) (ClassStaticAssert<e>())
int main()
{
    STATIC_ASSERT(0);
    return 0;
}
1 голос
/ 18 июля 2015
template <int a, int b>
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<foo, fum>(); // compiles ok
    static_assert_equal<foo, bar>(); // fails at compile time
    return 0;
}

Это происходит от checked_delete идиома.

1 голос
/ 17 мая 2013

Похоже на решение iammillind, которое, к сожалению, было полезно только во время выполнения:

template <int A, int B>
class VALUES { 
};

// specialization to provide safe passage for equal values        
template <int X>
class VALUES<X, X> {
public:
   static void MY_VALUES_ARE_EQUAL() {}
};


#define ASSERT_EQUALITY(a, b)    \
{    \
   typedef VALUES<a, b> 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 <int A, int B>
class VALUES {
public:
   static void AreEqual(EQUAL_VALUES_ONLY_PLEASE) {}
};

template <int X>
class VALUES<X, X>
{
public:
   static void AreEqual(COMPILE_TIME_EQUALITY_ASSERTION) {}
};


#define ASSERT_EQUALITY(a, b)                                   \
{                                                               \
   VALUES<a, b>::AreEqual(compiler_message);                             \
}

int main() {
    ASSERT_EQUALITY(1, 1) // a-okay
    ASSERT_EQUALITY(1, 2) // ERROR!
}

Я получаю следующие ошибки компилятора:

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]

комбинации статических функций-членов / конструкторов / назначения полей / конфиденциальности и спецификаций шаблонов могут привести к различным результатам, возможно, более подходящимдля вашей ситуации.

0 голосов
/ 04 декабря 2014

Предлагаю взглянуть на механизм статического утверждения библиотеки Eigen:

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

0 голосов
/ 20 июля 2011

Я бы выбрал один из доступных static_asserts.

  • boost :: static_assert
  • C ++ 0x static_assert

Но только потому, что яникогда не пробовал, прежде чем я написал это:

enum { foo=263, bar=264 };

template<bool test>
struct CompileAssert
{
    bool assert() {}
};

template<>
struct CompileAssert<false>  {}; // fail on false.

int main()
{
    CompileAssert<foo != bar>().assert();  // Now I have seen Chad above I like his static 
    CompileAssert<foo == bar>().assert();  // method better than using a normal method.
}                                          // But I tried zero length arrays first did 
                                           // not seem to work
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...