...

среда, 28 августа 2013 г.

Отказываемся от шаблонных шаблонных параметров

Использовать шаблонные шаблонные параметры С++ довольно сложно. Хочу продемонстрировать силу boost::mpl и показать трюк, позволяющий описывать шаблоны, полностью отказавшись от шаблонных шаблонных параметров.

Продемонстрирую проблему. Есть класс, принимающий тип объекта и тип контейнера для этого объекта.

template <typename T, typename Container>
struct A
{
typedef Container<T> type;
};




Так писать нельзя, вы должны использовать шаблонные шаблонные параметры, чтобы указать, что Container сам по себе является шаблоном.



Правильно написать так:

template <typename T, template<typename> class Container>
struct A
{
typedef Container<T> type;
};




Использовать так:

typedef A<int, std::vector>::type type;




При первом же использовании мы получим ошибку компиляции. Мы забыли, что std::vector принимает два параметра, один из которых обычно используется по умолчанию. Хорошо, перепишем:

template <typename T, template<typename, typename> class Container>
struct A
{
typedef Container<T, std::allocator<T> > type;
};




Тут две явные проблемы:


  1. Мы должны заглянуть в реализацию std::vector, выяснить, какой тип аллокатора используется по умолчанию, и тогда использовать его.

  2. Написанный нами шаблон не подойдёт, если у контейнера больше одного шаблонного параметра по умолчанию.




Хотелось бы избежать явного указания типов по умолчанию и сложного синтаксиса шаблонных шаблонных параметров. На помощь приходит приём, основанный на использовании плейсхолдеров из boost::mpl, которые используются для создания лямбда метафункций.

Внешне разница лишь в том, что нужно передавать в наш шаблон не сам шаблон контейнера, а инстанцированный плейсхолдером шаблон контейнера, то есть вместо



typedef A<int, std::vector>::type type;


пишем

typedef A<int, std::vector<boost::mpl::_1> >::type type;




Чтобы инстанцировать инстанцированный плейсхолдером контейнер нужным типом используем boost::mpl::apply:

#include <boost/mpl/apply.hpp>
template <typename T, typename Container>
struct A
{
typedef typename boost::mpl::apply<Container, T>::type type;
};




Использование этого трюка в реальном программировании поможет упростить некоторые ваши запутанные шаблоны.

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



Комментариев нет:

Отправить комментарий