Что делает static_assert и для чего бы вы его использовали?

StackOverflow https://stackoverflow.com/questions/1647895

Вопрос

Не могли бы вы привести пример, где static_assert(...) 'C++0x' могли бы вы элегантно решить стоящую перед вами проблему?

Я знаком со временем выполнения assert(...).Когда я должен предпочесть static_assert(...) слишком регулярно assert(...)?

Кроме того, в boost есть нечто, называемое BOOST_STATIC_ASSERT, это то же самое , что static_assert(...)?

Это было полезно?

Решение

С макушки головы ...

#include "SomeLibrary.h"

static_assert(SomeLibrary::Version > 2, 
         "Old versions of SomeLibrary are missing the foo functionality.  Cannot proceed!");

class UsingSomeLibrary {
   // ...
};

Предполагая, что SomeLibrary :: Version объявлен как статическая константа, а не как #define d (как и следовало ожидать в библиотеке C ++).

Сравните с необходимостью фактически скомпилировать SomeLibrary и ваш код, связать все и запустить только затем исполняемый файл, чтобы выяснить, что вы потратили 30 минут на компиляцию несовместимой версии <код> SomeLibrary .

@Arak, в ответ на ваш комментарий: да, у вас может быть static_assert , где бы вы ни находились, по его виду:

class Foo
{
    public: 
        static const int bar = 3;
};

static_assert(Foo::bar > 4, "Foo::bar is too small :(");

int main()
{ 
    return Foo::bar;
}
$ g++ --std=c++0x a.cpp
a.cpp:7: error: static assertion failed: "Foo::bar is too small :("

Другие советы

Статическое утверждение используется для создания утверждений во время компиляции. Когда статическое утверждение не выполняется, программа просто не компилируется. Это полезно в различных ситуациях, например, если вы реализуете некоторые функции с помощью кода, который критически зависит от объекта unsigned int , имеющего ровно 32 бита. Вы можете поместить статическое утверждение, как это

static_assert(sizeof(unsigned int) * CHAR_BIT == 32);

в вашем коде. На другой платформе с типом unsigned int другого размера компиляция завершится неудачно, что привлечет внимание разработчика к проблемной части кода и посоветует им повторно внедрить или повторно проверить его.

В другом примере вам может потребоваться передать некое интегральное значение в виде указателя void * на функцию (взломать, но иногда полезно), и вы хотите убедиться, что интегральное значение будет вписаться в указатель

int i;

static_assert(sizeof(void *) >= sizeof i);
foo((void *) i);

Возможно, вы захотите использовать этот тип char со знаком

static_assert(CHAR_MIN < 0);

или это интегральное деление с отрицательными значениями округляет до нуля

static_assert(-5 / 2 == -2);

И так далее.

Утверждения времени выполнения во многих случаях могут использоваться вместо статических утверждений, но утверждения времени выполнения работают только во время выполнения и только тогда, когда управление передает утверждение. По этой причине ошибочное утверждение во время выполнения может оставаться неактивным, необнаруженным в течение продолжительных периодов времени.

Конечно, выражение в статическом утверждении должно быть константой времени компиляции. Это не может быть значением времени выполнения. Для значений времени выполнения у вас нет другого выбора, кроме как использовать обычный assert .

Я использую его, чтобы убедиться, что мои предположения о поведении компилятора, заголовках, библиотеках и даже моем собственном коде верны. Например, здесь я проверяю, что структура была правильно упакована до ожидаемого размера.

struct LogicalBlockAddress
{
#pragma pack(push, 1)
    Uint32 logicalBlockNumber;
    Uint16 partitionReferenceNumber;
#pragma pack(pop)
};
BOOST_STATIC_ASSERT(sizeof(LogicalBlockAddress) == 6);

В stse.h класса, обертывающем fseek () , я взял несколько ярлыков с помощью enum Origin и проверил, что эти ярлыки выровнять с константами, определенными stdio.h

uint64_t BasicFile::seek(int64_t offset, enum Origin origin)
{
    BOOST_STATIC_ASSERT(SEEK_SET == Origin::SET);

Вы должны предпочесть static_assert , а не assert , когда поведение определяется во время компиляции, а не во время выполнения, как в приведенных выше примерах. Пример, в котором это не , будет включать проверку параметров и кода возврата.

BOOST_STATIC_ASSERT - это макрос до C ++ 0x, который генерирует недопустимый код, если условие не выполняется. Намерения те же, хотя static_assert стандартизирован и может обеспечить лучшую диагностику компилятора.

BOOST_STATIC_ASSERT является кроссплатформенной оболочкой для static_assert функциональность.

В настоящее время я использую static_assert для того, чтобы применить "Концепции" к классу.

пример:

template <typename T, typename U>
struct Type
{
  BOOST_STATIC_ASSERT(boost::is_base_of<T, Interface>::value);
  BOOST_STATIC_ASSERT(std::numeric_limits<U>::is_integer);
  /* ... more code ... */
};

Это вызовет ошибку времени компиляции, если какое-либо из вышеперечисленных условий не будет выполнено.

Одно из применений static_assert может заключаться в том, чтобы гарантировать, что структура (то есть интерфейс с внешним миром, таким как сеть или файл) - это именно тот размер, который вы ожидаете. Это будет отлавливать случаи, когда кто-то добавляет или изменяет член из структуры, не осознавая последствий. static_assert поднимет его и предупредит пользователя.

В отсутствие концепций можно использовать static_assert для простой и удобочитаемой проверки типов во время компиляции, например, в шаблонах:

template <class T>
void MyFunc(T value)
{
static_assert(std::is_base_of<MyBase, T>::value, 
              "T must be derived from MyBase");

// ...
}

Это не дает прямого ответа на исходный вопрос, но делает интересное исследование о том, как применять эти проверки времени компиляции до C ++ 11.

Глава 2 (раздел 2.1) из современного дизайна C ++ Андрея Александерску реализует это Идея утверждений времени компиляции, как это

template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};

#define STATIC_CHECK(expr, msg) \
{ CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } 

Сравните макросы STATIC_CHECK () и static_assert ()

STATIC_CHECK(0, COMPILATION_FAILED);
static_assert(0, "compilation failed");
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top