Метапрограммирование на C++ — различия между версиями
Строка 1: | Строка 1: | ||
Мы рассмотрим несколько техник использования шаблонов C++. | Мы рассмотрим несколько техник использования шаблонов C++. | ||
− | == Статический assert == | + | == Статический <code>assert</code> == |
В следующем примере приведен код, который компилируется только | В следующем примере приведен код, который компилируется только | ||
на 64-разрядной платформе: | на 64-разрядной платформе: | ||
Строка 10: | Строка 10: | ||
Если код компилируется не на 64-разрядной платформе, то | Если код компилируется не на 64-разрядной платформе, то | ||
− | sizeof(int*) != 8, что приведет к объявлению массива a отрицательного | + | <code>sizeof(int*) != 8</code>, что приведет к объявлению массива a отрицательного |
размера, а это запрещено стандартом. | размера, а это запрещено стандартом. | ||
− | Эта идея используется в макросе BOOST_STATIC_ASSERT, предоставляемом | + | Эта идея используется в макросе <code>BOOST_STATIC_ASSERT</code>, предоставляемом |
− | модулем Static Assert библиотеки Boost. | + | модулем <code>Static Assert</code> библиотеки <code>Boost</code>. |
== Tag passing == | == Tag passing == | ||
Строка 26: | Строка 26: | ||
</source> | </source> | ||
− | где p, q --- итераторы, указывающие на начало и конец массива, а элемент, | + | где <code>p</code>, <code>q</code> --- итераторы, указывающие на начало и конец массива, |
− | на который указывает m, после завершения работы функции будет располагаться | + | а элемент, на который указывает <code>m</code>, после завершения работы функции будет располагаться |
− | на месте элемента, на который указывает p. | + | на месте элемента, на который указывает <code>p</code>. |
Допустим, у нас есть разные реализации этой функции для разных типов итераторов: | Допустим, у нас есть разные реализации этой функции для разных типов итераторов: |
Версия 16:35, 7 мая 2011
Мы рассмотрим несколько техник использования шаблонов C++.
Содержание
Статический assert
В следующем примере приведен код, который компилируется только на 64-разрядной платформе:
char[sizeof(int*)] == 8 ? 1 : -1]
Если код компилируется не на 64-разрядной платформе, то
sizeof(int*) != 8
, что приведет к объявлению массива a отрицательного
размера, а это запрещено стандартом.
Эта идея используется в макросе BOOST_STATIC_ASSERT
, предоставляемом
модулем Static Assert
библиотеки Boost
.
Tag passing
Предположим, нам нужно написать функцию, которая циклически переставляет элементы массива:
template<typename It>
void rotate(It p, It, m, It q);
где p
, q
--- итераторы, указывающие на начало и конец массива,
а элемент, на который указывает m
, после завершения работы функции будет располагаться
на месте элемента, на который указывает p
.
Допустим, у нас есть разные реализации этой функции для разных типов итераторов:
template<typename It>
void rotate_bidirectional(It p, It, m, It q);
...
template<typename It>
void rotate_random_access(It p, It, m, It q);
Мы можем добавить к сигнатуре этих функций формальный параметр и перенести информацию о типе итератора, с которым работает эта функция из ее имени в этот параметр:
template<typename It>
void rotate(It p, It, m, It q, bidirectional_tag);
...
template<typename It>
void rotate(It p, It, m, It q, random_access_tag);
Тогда исходную функцию можно реализовать так:
template<typename It>
void rotate(It p, It, m, It q) {
rotate(p, m, q, iterator_traits<It>::iterator_category());
}
Замена числовых идентификаторов на типы
С помощью следующего трюка можно переписать функции, поведение которой зависит от числового идентификатора, на так, чтобы ее поведение зависело от формального параметра (как в предыдущем разделе):
void foo(int);
Мы можем определить шаблонную структуру:
template<int i>
struct int2type {
static const int value = i;
}
Теперь функцию foo можно переписать так:
template<int i>
void foo(int2type<i>);