Интересной особенностью таких функций, как<at>, при применении кForward Sequence, как<list>, является то, что то, что могло бы быть линейной сложностью выполнения, эффективно становится постоянным O(1) из-за оптимизации компилятором встроенных функций C++, хотя и глубоко рекурсивных (до определенного предела компилятора, конечно). Сложность компиляции времени остается линейной.
Ассоциативные последовательности используют перегрузку функций для реализации тестирования членства и поиска связанных ключей. Это равносильно постоянному времени выполнения и амортизированным постоянным сложностям компиляции времени. Есть перегруженная функция<f(k)>, для каждого ключатип<k>. Компилятор выбирает соответствующую функцию, заданную ключом<k>.
Отправка тегов - это общий метод программирования для выбора специализаций шаблонов. Как правило, в механизме отправки тегов участвуют 3 компонента:
- Тип, для которого требуется соответствующая специализация шаблона
- Метафункция, которая связывает тип с типом тега
- Шаблон, который специализируется на типе тега
Например, метафункция синтеза<result_of::begin>реализована следующим образом:
template <typename Sequence>
struct begin
{
typedef typename
result_of::begin_impl<typename traits::tag_of<Sequence>::type>::
template apply<Sequence>::type
type;
};
В случае:
- <
Sequence>является типом, для которого требуется подходящая реализация<result_of::begin_impl>.
- <
traits::tag_of>— это метафункция, которая связывает<Sequence>с соответствующим тегом.
- <
result_of::begin_impl>является шаблоном, который специализирован для обеспечения реализации для каждого типа тега.
В отличие отMPL, в слиянии нет расширяемой последовательности. Это не означает, что последовательности Fusion не расширяемы. Фактически, все последовательности Fusion по своей сути расширяемы. Просто способ расширения последовательности в Fusion отличается отSTLиMPLиз-за ленивой природы слиянийАлгоритмы.STLконтейнеры расширяются на месте, хотя членские функции, такие как<push_back>и<insert>.MPLпоследовательности, с другой стороны, расширяются через «внутренние» функции, которые фактически возвращают целые последовательности.MPLчисто функциональна и не может иметь побочных эффектов. Например,MPL's<push_back>фактически не мутирует<mpl::vector>. Этого не может быть. Вместо этого он возвращает расширенный<mpl::vector>.
Как иMPL, Fusion тоже чисто функциональна и не может иметь побочных эффектов. С учетом эффективности времени выполнения последовательности Fusion расширяются за счет общих функций, которые возвращаютПросмотры.Видыпредставляют собой последовательности, которые фактически не содержат данных, а вместо этого передают альтернативное представление по данным из одной или нескольких базовых последовательностей.Видыявляются прокси. Они обеспечивают эффективный, но чисто функциональный способ работы с потенциально дорогостоящими операциями последовательности. Например, учитывая<vector>, Fusion<push_back>возвращает<joint_view>, вместо фактического расширенного<vector>. A<joint_view>содержит ссылку на оригинальную последовательность плюс прилагаемые данные, что делает ее очень дешевой для передачи.
Функции, которые принимают элементарные значения для формирования последовательностей (например,<make_list>), преобразуют свои аргументы во что-то подходящее для хранения в качестве элемента последовательности. В общем, типы элементов хранятся в виде простых значений. Пример:
make_list(1, 'x')
<list><<int,
char>>возвращает.
Однако есть несколько исключений.
Решетки:
Аргументы массива выводятся для ссылки на типы const.:
make_list("Donald", "Daisy")
<list>[]
list<const char (&)[7], const char (&)[6]>
Функциональные указатели:
Функциональные указатели выводятся на простой нессылочный тип (т.е. на простой функциональный указатель). Пример:
void f(int i);
...
make_list(&f);
<list>[]
list<void (*)(int)>
Функции генерации Fusion (например,<make_list>) по умолчанию хранит типы элементов в виде простых нессылочных типов. Пример:
void foo(const A& a, B& b) {
...
make_list(a, b)
<list>[]
list<A, B>
Иногда простой нессылочный тип нежелателен. Вы можете использовать<boost::ref>и<boost::cref>для хранения ссылок или ссылок (соответственно). Механизм не компрометирует правильность const, поскольку объект const, завернутый ref, приводит к элементу кортежа с эталонным типом const (см. пятую строку кода ниже). Примеры:
Например:
A a; B b; const A ca = a;
make_list(cref(a), b);
make_list(ref(a), b);
make_list(ref(a), cref(b));
make_list(cref(ca));
make_list(ref(ca));
См.Boost.Refдля деталей.
Начиная с C++11 работают также стандартные обертки ссылок<std::ref>и<std::cref>.
Для адаптации произвольных типов данных, которые не допускают прямого доступа к своим членам, но позволяют косвенный доступ через выражения (такие как вызовы get- и set-методов), может использоваться семейство fusion<BOOST_FUSION_ADAPT_xxxADTxxx>(например,<BOOST_FUSION_ADAPT_ADT>). Чтобы обойти ограничение, не имеющее фактических значений l, которые представляют элементы последовательности синтеза, а скорее последовательность парных выражений, которые получают доступ к элементам, фактический тип возврата функций доступа к внутренней последовательности синтеза<at>,<at_c>,<at_key>,<deref>и<deref_data>является прокси-типом, экземпляром<adt_attribute_proxy>, который инкапсулирует эти выражения.
<adt_attribute_proxy>определяется в пространстве имен<boost::fusion::extension>и имеет три шаблонных аргумента:
namespace boost { namespace fusion { namespace extension
{
template<
typename Type
, int Index
, bool Const
>
struct adt_attribute_proxy;
}}}
При адаптации типа класса<adt_attribute_proxy>специализируется на каждом элементе адаптированной последовательности, причем<Type>является типом класса, который адаптирован,<Index>основанными на 0 индексами элементов и<Const>как<true>, так и<false>. Возвратный тип функции доступа к внутренней последовательности слияния дляNэлемента адаптированного типа класса<type_name>является<adt_attribute_proxy<type_name,N,Const>>, причем<Const>является<true>для постоянных экземпляров<type_name>и<false>для непостоянных.
Notation
type_name
Тип, подлежащий адаптации, с атрибутами M
inst
Объект типа<type_name>
const_inst
Объект типа<type_nameconst>
(attribute_typeN, attribute_const_typeN,
get_exprN, set_exprN)
Атрибутный дескрипторNатрибута<type_name>, переданный макросу адаптации, 0≤N
proxy_typeN
<adt_attribute_proxy<type_name,N,false>>сNбудучи интегральной постоянной, 0≤N
const_proxy_typeN
<adt_attribute_proxy<type_name,N,true>>сNбудучи интегральной постоянной, 0≤N
proxyN
Объект типа<proxy_typeN>
const_proxyN
Объект типа<const_proxy_typeN>
Семантика экспрессии
Кроме того,<proxy_typeN>и<const_proxy_typeN>являются копируемыми конструируемыми, присваиваемыми копиями и неявно конвертируемыми в<proxy_typeN::type>или<const_proxy_typeN::type>.
![[Tip]](/img/tip.png) |
Tip |
Чтобы избежать ловушек прокси-типа, произвольный тип класса также может быть адаптирован непосредственно с использованием внутреннего механизма расширения синтеза. |