Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
template_metaprogramming_ru.docx
Скачиваний:
12
Добавлен:
01.07.2025
Размер:
774 Кб
Скачать
☆

(Статические Утверждения)

Позволяют генерировать ошибку, когда обнаруживается неправильное использование кода:

BOOST_STATIC_ASSERT(integral-constant-expression);

Если выражение ложно (0), то выдается ошибка компиляции. Утверждения лучше всего использовать, чтобы убедиться, что предположения, при которых код был написан соответсвуют утверждению.

Пример метафункции расчета факториала:

template <class N>

struct factorial

: mpl::eval_if<

mpl::equal_to<N,mpl::int_<0>>, // check N == 0

mpl::int_<1>, // 0! == 1

mpl::multiplies< // N! == N * (N-1)!

N,

factorial<typename mpl::prior<N>::type>

>

>

{

BOOST_STATIC_ASSERT(N::value >= 0); // for nonnegative N

};

Вычисление факториала N! имеет смысл только при неотрицательном N, что и проверяет утверждение.

Если написать:

int const fact = factorial<mpl::int_<-6>>::value;

то получлим следующий дамп (Intel C++ 8.1):

foo.cpp(22): error: incomplete type is not allowed

BOOST_STATIC_ASSERT(N::value >= 0);

^

detected during instantiation of class "factorial<N>

[with N=mpl_::int_<-6>]" at line 25

Когда условие нарушается, то в сообщении об ошибке будеь указана строка, содержащая нарушенное утверждение. Т.о., мкрос BOOST_STATIC_ASSERT помогает компилятору разобраться в причинах ошибки.

Содержание диагностического сообщения выше вряд ли может быть более информативным: не только является источником линии отображаются, но мы видим, условия в вопросе и аргумент для факториала. В целом, однако, вы не можете полагаться на такие полезные результаты BOOST_STATIC_ASSERT. В этом случае мы получили их по более счастливой случайности, чем дизайн.

Многие компиляторы, в случае не срабатывания утверждения, не показывают строку с кодом утвреждения, в сообщении об ошибке (GCC 3.3.1):

foo.cpp: In instantiation of 'factorial<mpl_::int_<-6> >':

foo.cpp:25: instantiated from here

foo.cpp:22: error: invalid application of 'sizeof' to an

incomplete type

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

BOOST_MPL_ASSERT

Формат:

BOOST_MPL_ASSERT((bool-valued-nullary-metafunction))

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

Применим данный макрос к примеру с ошибочным использованием факториала:

#include <boost/mpl/greater_equal.hpp>

#include <boost/mpl/assert.hpp>

template <class N>

struct factorial

// ...

{

BOOST_MPL_ASSERT((mpl::greater_equal<N,mpl::int_<0>>));

};

Преимущество макроса BOOST_MPL_ASSERT в том, что имя его аргумента будет выведено в диагностике (GCC):

foo.cpp: In instantiation of 'factorial<mpl_::int_<-6> >':

foo.cpp:26: instantiated from here

foo.cpp:23: error: conversion from '

mpl_::failed**********boost::mpl::greater_equal<mpl_::int_<-6>,

mpl_::int_<0> >::***********' to non-scalar type '

mpl_::assert<false>' requested

foo.cpp:23: error: enumerator value for '

mpl_assertion_in_line_23' not integer constant

Нарушеные условия заключенны в последовательности звездочек.

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

BOOST_MPL_ASSERT((boost::is_integral<typename N::value_type>));

Чтобы запустить это утверждение, мы могли бы написать:

// attempt to make a "floating point constant wrapper"

struct five : mpl::int_<5> { typedef double value_type; }; // переопределим тип аргумента в обертке int_<5>.

int const fact = factorial<five>::value;

Диагностика:

...

foo.cpp:24: error: conversion from

'mpl_::failed************boost::is_integral<double>::************'

to non-scalar type 'mpl_::assert<false>' requested

...

BOOST_MPL_ASSERT_NOT

Чтобы проверять отрицательные условия с макросами BOOST_STATIC_ASSERT или BOOST_MPL_ASSERT, необходимо использовать обертку-предикат mpl::not_<...>.

Чтобы упростить отрицательные утверждения, MPL предоставляет маркос BOOST_MPL_ASSERT_NOT, который применяет данную обертку неявно.

Применение:

BOOST_MPL_ASSERT_NOT((mpl::less<N,mpl::int_<0>>));

То, что за макросом стоит обертка видно из сообщения об ошибке:

foo.cpp:24: error: conversion from 'mpl_::failed

************boost::mpl::not_<boost::mpl::less<mpl_::int_<-5>,

mpl_::int_<0> > >::************' to non-scalar type

'mpl_::assert<false>' requested

BOOST_MPL_ASSERT_RELATION

BOOST_MPL_ASSERT не очень хорошо подходит для проверки численных условий, поскольку диагностика и утверждения сопряжены и так с большими синтаксическими накладными расходами. Написание mpl::greater_equal <x,y>, для проверки, что х >= у, не выполняется, в общем случае, напрямую. Для такого рода численных сравнений, MPL предоставляет специализированный макрос.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]