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

Майерс Скотт

Шрифт:

Рассмотрим псевдокод шаблонной функции advance, представленный на стр. 227 (см. правило 47; возможно, имеет смысл перечитать это правило сейчас, поскольку ниже я предполагаю, что вы знакомы с изложенным в нем материалом). Я выделил в этом фрагменте часть, написанную на псевдокоде:

template<typename IterT, typename DistT>

void advance(IterT& iter, DistT d)

{

if (iter является итератором с произвольным доступом) {

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

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

else {

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

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

}

}

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

template<typename IterT, typename DistT>

void advance(IterT& iter, DistT d)

{

if (typeid(typename std::iterator_traits<IterT>::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<int>::iterator iter;

...

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

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

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

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

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

{

if (typeid(std::iterator_traits<std::list<int>::iterator>::iterator_category)==

typeid(std::random_access_iterator_tag))

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

}

else {

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

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

}

}

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

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

  • Читать дальше
  • 1
  • ...
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: