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

Композиция классов

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

Например, генерирование структуры класса, но основе последовательности типов. Для раскрутки последовательности применим алгоритм fold:

// fine-grained struct element; stores a T and inherits More

template <class T, class More>

struct store : More

{

T value;

};

typedef mpl::vector<short[2], long, char*, int> member_types;

struct empty {};

mpl::fold<

member_types, empty, store<_2,_1>

>::type generated;

Сгенерированная структура типов имеет следующий вид:

store<int,

store<char*,

store<long,

store<short[2], empty>

>

>

>

Каждая специализация store, представляет собой отдельный уровень в сгенерированной иерархии наследования, инциализированный отдельным типом из списка member_types.

Использование комползиции классов таким образом может быть затруднительно если они недостаточно структурированы. Сложность состоит в доступе к каждому отдельному типу, т.к. все имеют идентичное имя «::value» с разной степень вложенности. (Для организации такого доступа можно использовать метапрограммирование препроцессора.)

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

long& x = static_cast<store<long, store<short[2], empty>>&>(generated).value;

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

template <class T, class U>

store<T, U> const& get(store<T, U> const& e)

{

return e;

}

char* s = get<char*>(generated).value;

В приведенном выше примере, первый шаблонный параметр будет инициализирован типом char*, а действительный параметр функции shore<char*,U> const&, который соответствует базовому классу, содержащему сгенерированный элемент типа char*.

Упростим данное решение, добавив дополнительный уровень абстракции (Фундаментальная Теорема Программирования).

// fine-grained struct element; wraps a T

template <class T>

struct wrap

{

T value;

};

// one more level of indirection

template <class U, class V>

struct inherit : U, V

{};

typedef mpl::vector<short[2], long, char*, int> member_types;

struct empty {};

mpl::fold<

member_types, empty, inherit<wrap<_2>,_1>

>::type generated;

Сгенерированная структура типов имеет следующий вид:

inherit<wrap<int>,

inherit<wrap<char*>,

inherit<wrap<long>,

inherit<wrap<short[2]>,

empty

>

>

>

>

Т.к. inherit<U,V> наследует оба класса U и V, то для каждого типа из списка будет создан индивидуальный базовый класс (без хвоста типов), что позволит проще получить к нему доступ:

long& x = static_cast<wrap<long> &>(generated).value;

Генерирование классов таким образом является фундаментальной метапрограммной деятельностью, поэтому MPL предоставляет готовые средства для решения подобных задач. В частности, можно заменить empty и inherit на mpl::empty_base и mpl::inherit. Библиотека также содержит соответствующую метафункцию inherit_linearly, которая вызывает fold с типом параметра по умолчанию mpl::empty_base:

template <class Types, class Node, class Root = empty_base>

struct inherit_linearly

: fold<Types,Root,Node>

{};

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

#include <boost/mpl/inherit.hpp>

#include <boost/mpl/inherit_linearly.hpp>

#include <boost/mpl/vector.hpp>

// fine-grained struct element

template <class T>

struct wrap

{

T value;

};

typedef mpl::vector<short[2], long, char*, int> member_types;

mpl::inherit_linearly<

member_types, mpl::inherit<wrap<_2>,_1>

>::type generated;

int main()

{

long& x = static_cast<wrap<long>&>(generated).value;

cout << x << endl;

return 0;

}

Эти механизмы были подробно исследованы Андреем Александреску. Например, им используется композиция классов для генерации посетителей для обобщенного множественного выбора сред.

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