2010-05-25 2 views
5

Статические утверждения очень удобны для проверки во время компиляции. Простая статическая утверждают идиома выглядит следующим образом:static assert для константных переменных?

template<bool> struct StaticAssert; 
template<> struct StaticAssert<true> {}; 

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0) 

Это хорошо для вещей, как

STATIC_ASSERT(sizeof(float) == 4) 

и:

#define THIS_LIMIT (1000) 
... 
STATIC_ASSERT(THIS_LIMIT > OTHER_LIMIT); 

Но использование #define не "C++" способ определения константы. C++ бы использовать анонимное пространство имен:

namespace { 
    const int THIS_LIMIT = 1000; 
} 

или даже:

static const int THIS_LIMIT = 1000; 

Проблема в том, что с const int вы не можете использовать STATIC_ASSERT() и вы должны прибегнуть к времени выполнения проверьте, что глупо.

Есть ли способ правильно решить эту проблему в текущем C++?
Я думаю, что я читал C++ 0x имеет некоторое средство, чтобы сделать это ...


EDIT

ИТАК это

static const int THIS_LIMIT = 1000; 
... 
STATIC_ASSERT(THIS_LIMIT > 0); 

отлично компилируется
Но это:

static const float THIS_LIMIT = 1000.0f; 
... 
STATIC_ASSERT(THIS_LIMIT > 0.0f); 

нет.
(в Visual Studio 2008)

Почему?

+0

Почему вы используете статическое утверждение NIH вместо BOOST_STATIC_ASSERT? http://www.boost.org/doc/libs/1_43_0/doc/html/boost_staticassert.html –

+0

Я не могу использовать boost (пока) по какой-то глупой корпоративной причине – shoosh

+1

Что заставляет вас думать, что вы не можете использовать интегральные константы в этом случае? Вышеизложенное должно работать нормально. –

ответ

10

Почему, вы можете по-прежнему статические утверждают с сопзЬ междунар:

#define static_assert(e) extern char (*ct_assert(void)) [sizeof(char[1 - 2*!(e)])] 
static_assert(THIS_LIMIT > OTHER_LIMIT) 

Кроме того, use boost!

BOOST_STATIC_ASSERT(THIS_LIMIT > OTHER_LIMIT) 

... вы получите намного приятнее сообщения об ошибках ...

+0

Ну, для меня есть урок. не говорите, что что-то невозможно, прежде чем пытаться это сделать ... – shoosh

+0

Я все еще задаюсь вопросом, какую проблему следует исправить? –

+0

@shoosh: Оригинальный код должен компилироваться в порядке. См. [Мой ответ] (http://stackoverflow.com/questions/2902917/2903013#2903013). – sbi

1

Возможно, вы путаете поведение C++ 's с C, где const int не представляет собой истинную константу времени компиляции. Или, возможно, ваш компилятор C++ поврежден. Если это действительно последнее, используйте вместо этого enum.

+0

у вас есть +1, я получил -1 для того же решения =/ –

+0

@Viktor Sehr: Чтобы быть справедливым, мой ответ дает объяснение mores, чем ваше, и использование 'enum' should * not * необходимо в C++ для этого случая. – jamesdlin

+0

@ViktorSehr: Это место не о том, чтобы выкидывать «решения» в фрагменты кода, как будто они были кусками мяса; речь идет о написании _answers_ для объяснения, обучения и информирования. Часто хорошие ответы включают иллюстрации кода, но это не означает, что ответ, который состоит из кода, является хорошим. Действительно, это редкость. –

1

Это:

namespace { 
    const int THIS_LIMIT = 1000; 
} 

template<bool> struct StaticAssert; 
template<> struct StaticAssert<true> {}; 

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0) 

int main() 
{ 
    STATIC_ASSERT(THIS_LIMIT > 5); 

    return (0); 
} 

компилируется нормально с ВК и Комео.

0

enum{THIS_LIMIT = 1000};

+0

Почему -1 голос? –

+1

Я не спустил вас вниз, но это вряд ли ответ на данный вопрос. Это допустимый способ обхода, и это действительный код, но вы указали нулевое описание, нулевое объяснение и нулевой анализ (a), что он делает, (b) как он отличается от кода OP и (c) почему он должен использоваться (и , на самом деле это не должно быть). Следовательно, это кажется немного ленивым, и, вероятно, поэтому оно было опущено. На самом деле, подумайте об этом, я собираюсь понизить его и по этой причине. Сожалею. –

+0

Не беспокойтесь, я думаю, вы предоставили довольно хорошее объяснение :) –

4

static_assert особенность компилятор C++ 0x так до тех пор, как у вас есть компилятор относительно последнюю дату, вы можете использовать это.Следите за тем, чтобы делать #define static_assert(x) ..., потому что это ключевое слово реального в C++ 0x, чтобы вы постоянно скрывали функцию компилятора. Кроме того, C++ 0x static_assert принимает два параметра (например, static_assert(sizeof(int) == 4, "Expecting int to be 4 bytes")), поэтому вы можете столкнуться с проблемами при попытке переключиться в будущем, если используете этот #define.

2

Кажется, что ты на самом деле вопросом, почему следующий случай (и я могу подтвердить, что в обоих GCC 4.3.4 и Visual C++ 2008 Express):

template<bool> struct StaticAssert; 
template<> struct StaticAssert<true> {}; 

#define STATIC_ASSERT(condition) do { StaticAssert<(condition)>(); } while(0) 


static const int AN_INT = 1000; 
static const float A_FLOAT = 1000.0f; 

int main() 
{ 
    STATIC_ASSERT(AN_INT > 0);  // OK 
    STATIC_ASSERT(A_FLOAT > 0.0f); // Error: A_FLOAT may not appear in a constant expression 
} 

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

[C++11: 5.19/2]:условно-выражение является постоянным выражением ядра, если она не включает в себя одно из следующих действий как потенциально оцениваемой подвыражению (3.2), но подвыражения логическое И (5.14), логический OR (5.15) и условные (5.16) операции, которые не оцениваются, не считаются [Примечание: Перегруженный оператор вызывает функцию . -end примечание] :

  • [..]
  • именующее-к-RValue преобразования (4.1), если оно не применяется к
    • в glvalue интеграла или перечисления тип, который относится к энергонезависимому объекту const с предшествующей инициализацией, инициализированному константным выражением, или
    • значение glvalue буквального типа, которое относится к неопределенный объект, определенный с помощью constexpr, или который относится к под-объекту такого объекта, или
    • : значение glvalue типа literal, которое относится к энергонезависимому временному объекту, срок службы которого еще не закончился, инициализирован константой выражение;
  • [..]

(т.е. только интегральные и перечисление типов не допускаются;. Никаких типов с плавающей точкой)

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

[C++11: 5.19/4]: [..] Поскольку этот международный стандарт не налагает никаких ограничений на точность операций с плавающей запятой , неясно, дает ли оценка выражения с плавающей запятой во время перевода, дает тот же результат, что и оценка того же выражения (или те же операции с теми же значениями) во время выполнения программы. [..]

Смежные вопросы