Что означает этот код? - PullRequest
       1

Что означает этот код?

1 голос
/ 28 января 2011

Это часть статического трюка с утверждениями.Я не могу понять, как работает неспециализированный класс.Кто-нибудь может мне это объяснить?

РЕДАКТИРОВАТЬ: Полный код с макросом: (взят из http://www.skynet.ie/~caolan/Fragments/C++StaticAssert.html)

#ifndef STATICASSERT_HXX
#define STATICASSERT_HXX
/*
 Lifted direct from:
 Modern C++ Design: Generic Programming and Design Patterns Applied
 Section 2.1
 by Andrei Alexandrescu
*/
namespace ww
{
    template<bool> class compile_time_check
    {
    public:
        compile_time_check(...) {}
    };

    template<> class compile_time_check<false>
    {
    };
}

    /*
    Similiar to assert, StaticAssert is only in operation when NDEBUG is not
    defined. It will test its first argument at compile time and on failure
    report the error message of the second argument, which must be a valid c++
    classname. i.e. no spaces, punctuation or reserved keywords.
    */
#ifndef NDEBUG
#   define StaticAssert(test, errormsg)                         \
    do {                                                        \
        struct ERROR_##errormsg {};                             \
        typedef ww::compile_time_check< (test) != 0 > tmplimpl; \
        tmplimpl aTemp = tmplimpl(ERROR_##errormsg());          \
        sizeof(aTemp);                                          \
    } while (0)
#else
#   define StaticAssert(test, errormsg)                         \
    do {} while (0)
#endif

#endif

Ответы [ 2 ]

5 голосов
/ 28 января 2011

Макрос вызывает этот код следующим образом:

compile_time_check<static expression> temp(Error_Some_Struct_here);

Так, например, вы можете сделать это:

compile_time_check<sizeof(Foo) < sizeof(Bar)> temp(Error_Foo_must_be_smaller_than_Bar);

Когда sizeof(Foo) меньшеsizeof(Bar), шаблон будет создавать неспециализованную версию:

template<bool> class compile_time_check
{
public:
    compile_time_check(...) {}  //What is this?
};

, а код в основном "компилируется" в экземпляр этого класса:

compile_time_check temp(Error_Foo_must_be_smaller_than_Bar);

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

Если, с другой стороны, sizeof(Foo) больше или равно sizeof(Bar), вместо этого будет создана специализированная версия:

template<> class compile_time_check<false>
{
};

и он попытается вызвать конструктор compile_time_check::compile_time_check(struct), но поскольку он не существует, это ошибка компиляции.Это именно то, что вам нужно, потому что статическое утверждение должно компилироваться только в том случае, если утверждение истинно.

Причина, по которой конструктор принимает список параметров с переменными параметрами, я полагаю, двойная:

  1. Чтобы убедиться, что он не вызывает конструктор по умолчанию, который имел бы специализированная версия.Его переменная, так что вы можете передать в любой структуре как «строку» ошибки.В качестве альтернативы, это могло быть шаблонно, и конструктор мог бы вместо этого взять объект шаблона в качестве аргумента.
  2. , чтобы можно было передать сообщение об ошибке. Когда утверждение равно true, это игнорируется, и ничего не происходит, икод удаляется оптимизатором компиляторов.Если assert ложно, однако, строка ошибки должна появиться в сообщении об ошибке.Что-то вроде constructor not found for compile_time_check::compile_time_check(ERROR_Assertion_error_blah()) возможно.

Альтернативный, без шаблонов (я полагаю, его часто используют в C) статический assert, который я видел где-то раньше, это:

#define compile_time_assert(pred) switch(0){case: 0: case pred:;}

Это работает, потому что если pred равно false, код будет иметь вид switch(0){case: 0: case 0:;}, а две метки регистра с одинаковой константой будут ошибкой. Подробное объяснение здесь .

3 голосов
/ 28 января 2011

Избавление от пространства имен на данный момент (поскольку оно в основном не имеет значения), то, что у вас есть:

template<bool> class compile_time_check
{
public:
    compile_time_check(...) {}  //What is this?
};

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

template<> class compile_time_check<false>
{
};

Это специализация предыдущего шаблона для значения false.Таким образом, когда вы создаете экземпляр compile_time_check<false> checker;, он будет использовать этот.Эта специализация имеет конструктор по умолчанию (он никогда не используется), но нет конструктор, который будет принимать параметр.

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

    typedef ww::compile_time_check< (test) != 0 > tmplimpl; \
    tmplimpl aTemp = tmplimpl(ERROR_##errormsg());          \
    sizeof(aTemp);                                          \

В этом случае мы создаем экземпляр объекта tmplimpl с параметром ctor.Если параметр шаблона был равен true, это будет работать, но если параметр шаблона был равен false, он будет использовать вышеуказанную специализацию, которая имеет только ctor по умолчанию, а не такую, которая будет принимать аргумент - поэтому компилятор выведет на печатьсообщение об ошибке, говорящее что-то вроде:

error: no ctor found for compile_time_check<condition>("<error message>");

Последующий sizeof(aTemp); предназначен для принудительной оценки этого объекта во время компиляции, поэтому мы видим это как сообщение об ошибке компилятора вместо ошибки компоновщика, говорящей, чтоcompile_time_check::compile_time_check<false>() является неразрешенным внешним.

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