Интересной особенностью таких функций, как<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 |
Чтобы избежать ловушек прокси-типа, произвольный тип класса также может быть адаптирован непосредственно с использованием внутреннего механизма расширения синтеза. |