Читаем Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ полностью

Мы можем использовать typeid, чтобы заменить псевдокод реальным кодом. Тогда задача будет решена «нормальным» для C++ способом – вся работа выполняется во время исполнения:

template

void advance(IterT& iter, DistT d)

{

if (typeid(typename std::iterator_traits::iterator_category)==

typeid(std::random_access_iterator_tag))

iter += d; // использовать итеративную арифметику

} // для итераторов с произвольным доступом

else {

if(d>=0) {while (d–) ++iter;} // вызывать ++ или – в цикле

else {while(d++) –iter;} // для итераторов других категорий

}

}

В правиле 47 отмечено, что подход, основанный на typeid, менее эффективен, чем при использовании классов-характеристик, поскольку в этом случае: (1) проверка типа происходит во время исполнения, а не во время компиляции, и (2) код, выполняющий проверку типа, должен быть включен в исполняемую программу. Фактически этот пример показывает, как технология TMP может порождать более эффективные программы на C++, потому что характеристики – это и есть частный случай TMP. Напомню, что характеристики делают возможным вычисление выражения if…else во время компиляции.

Я уже отмечал выше, что некоторые вещи технология TMP позволяет сделать проще, чем «нормальный» C++, и advance можно считать иллюстраций этого утверждения. В правиле 47 упоминается о том, что основанная на typeid реализация advance может привести к проблемам во время компиляции, и вот вам пример такой ситуации:

std::list::iterator iter;

...

advance(iter, 10); // сдвинуть iter на 10 элементов вперед

// не скомпилируется для приведенной

// выше реализации

Рассмотрим версию advance, которая будет сгенерирована для этого вызова. После подстановки типов iter и 10 в качестве параметров шаблона IterT и DistT мы получим следующее:

void advance(std::list::iterator& iter, int d)

{

if (typeid(std::iterator_traits::iterator>::iterator_category)==

typeid(std::random_access_iterator_tag))

iter += d; // ошибка!

}

else {

if(d>=0) {while (d–) ++iter;}

else {while(d++) –iter;}

}

}

Проблема в выделенной строке, где встречается оператор +=. В данном случае мы пытаемся использовать += для типа list::iterator, но list::iterator – это двунаправленный итератор (см. правило 47), поэтому он не поддерживает +=. Оператор += поддерживают только итераторы с произвольным доступом. Мы знаем, что никогда не попытаемся исполнить предложение, содержащее +=, потому что для list::iterator проверка с привлечением typeid никогда не выполнится успешно, но компилятор-то обязан гарантировать, что весь исходный код корректен, даже если он никогда не исполняется, а «iter += d» – некорректный код в случае, когда iter не является итератором с произвольным доступом. Решение же на основе технологии TMP предполагает, что код для разных типов вынесен в разные функции, каждая из которых использует только операции, применимые к типам, для которых она написана.

Было доказано, что технология TMP представляет собой полную машину Тьюринга, то есть обладает достаточной мощью для любых вычислений. Используя TMP, вы можете объявлять переменные, выполнять циклы, писать и вызывать функции и т. д. Но такие конструкции выглядят совершенно иначе, чем их аналоги из «нормального» C++. Например, в правиле 47 показано, как в TMP условные предложения if…else выражаются с помощью шаблонов и их специализаций. Но такие конструкции можно назвать «TMP уровня ассемблера». В библиотеках для работы с TMP (например, MPL из Boost – см. правило 55) предлагается более высокоуровневый синтаксис, хотя его также нельзя принять за «нормальный» С++.

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных

Все жанры