|
Программирование >> Обобщенные обратные вызовы
Решение 1 является несколько подчищенной версией кода, сохраняющей общую структуру исходного варианта, код сократился с 23 до 17 строк (даже если считать public: и private: отдельными строками), namespace Solutionl { tempiate<class lter> class sort idxtbl pai г { public: void setCconst lter& it, int i) {it = it; i = i;} bool operator<(const sort idxtbl pair& other) const { return *it < *other.it ; } operator int() const { return i ; } private: Iter it ; int i ; Эта функция претерпела самые существенные изменения, сократившись с 13 строк до 5. Для сравнения я сохранил весь старый код. Старайтесь писать программы так, чтобы в них не было излишней сложности tempiate<class iterin, class iterout> void sort idxtbl(iterin fi rst, iterin last, iterout out){ std::vector<sort idxtbl pair<iterin> > v(last-first); i nt iDst = 1ast-fi rst; typedef std::vector< sort idxtbl pair<RAlter> > V; V v(iDst); for( i nt i=0; i < 1ast-fi rst; ++i ) v[i].set( first+i, i ); . int i=0; RAlter it = first; v;:iterator vit = v.begin(); for (i=0; it<last; it++, vit++, i++) (*vit).set(it,i); std: :sort( v.beqin() , v.endO ) ; std::sort(v.begi n(), v.end()); std: : copy( v. begi n() , v.endO, out ) ; int *pi = pidxtbl; vit = V.beginO ; for (; vit<v.end(); pi++, vit++) *pi = (*vit) .i; Решение 2 использует класс pair вместо вспомогательного класса, код уменьшился до 15 строк (из них 2 - продолжение предыдущих из-за ширины страницы). 8 строк специфичны для данного кода, а 4 строки в принципе можно непосредственно использовать и в других контекстах. namespace Solution2 { tempiate<class т, class u> struct ComparePairlstDeref { bool operatorO(const std::pair<T,U>& a, const std::pair<T,u>& b ) const { return *a.first < *b.first; } tempiate<class Iterin, class Iter0ut> void sort idxtbl(Iterin fi rst, Iterin last, Iterout out){ std::vector< std::pair<iterin,int> > s( last-first ); for( int i=0; i < s.sizeO; ++i ) s[i] = std::make pair( first+i, i ); std: :sort(s.begin(), s.endO, ComparePai rlstDeref<lterln,int>()); for( int i=0; i < s.sizeC); ++i, ++out ) *out = s[i].second; Решение 3 демонстрирует пару альтернативных деталей - в нем используется тар для того, чтобы избежать отдельного этапа сортировки, и std::transformC) вместо вручную написанного цикла, код сократился до 16 строк и стал существенно более повторно используемым, этой версии требуется больше памяти и, вероятно, ее производительность немного ниже, так что мне больше нравится решение 2. Этот код - пример поиска альтернативного решения задачи. namespace solutions { tempiate<class т> struct CompareDeref { bool operatorOC const т& a, const т& b ) const { return *a < *b; } tempiate<class т, class u> struct Pair2nd { const u& operatorOC const std: :pai r<T,u>& a ) const { return a.second; } tempiate<class iterin, class Iter0ut> void sort idxtblCiterin fi rst, iterin last, Iterout out){ std::multimap<lterin, int, CompareDeref<IterIn> > v; forC int i=0; first != last; ++i, ++first ) v.insertC std::make pairC fi rst, i ) ); std::transform(v.begin(), v.endC), out, pair2nd<Iterln const,int>C)); тестовая часть кода осталась по сути неизменной, за исключением использования итератора для получения результата (вместо int*) и использования исходного массива непосредственно в качестве контейнера. #include <iostream> int main() { int ai[10] = { 15,12,13,14,18,11,10,17,16,19 }; std::cout ################# std::endl; std::vector<int> aidxtbl( 10 ); для тестирования другого решения используйте соответствующее имя пространства имен solutions::sort idxtbl( ai, ai+10, aidxtbl.begin() ); for( int i=0; i <10; ++i ) std::cout i= i , aidxtbl[i]= aidxtbl[i] , ai [aidxtbl [i]]= ai [aidxtbl [il] std: :endl; std::cout ################# std::endl; Задача 35. Обобщенные обратные вызовы Сложность: 5 Отчасти привлекательность обобщенного кода состоит в возможности его использования во всех ситуациях, которые только можно представить. Каким образом можно стилистически улучшить представленное в цитируемой статье средство, и каким образом можно сделать его более полезным, чтобы это был действительно обобщенный широко используемый код? Вопрос для новичка 1. Какие качества целесообразны при разработке и написании обобщенных средств? Поясните свой ответ. Вопрос для профессионала 2. Показанный далее код представляет интересную и очень полезную идиому для оболочек функций обратного вызова. Более детальное описание вы можете найти в оригинальной статье [KalevOl]. Отрецензируйте предложенный код и определите: а) возможные стилистические улучшения дизайна для лучшего идиоматического использования С++; б) механические ограничения полезности данного средства. template < class т, void (t::*f)() > class callback public: Присваивание члену object callback(t& t) : obiect(t) {} Запуск функции обратного вызова void executeO {(object.*f)();} private: t& object; Решение Качества обобщенности I. Какие качества целесообразны при разработке и написании обобщенных средств? Поясните свой ответ. Обобщенный код прежде всего должен быть практичен и удобен в использовании. Это не значит, что он должен включать все возможные варианты использования, включая варку кофе и мытье посуды. Это всего лишь означает, что в отношении обобщенного кода следует стараться избегать как минимум трех вещей. /. Избегайте чрезмерного ограничения типов. Например, если вы пишете обобщенный контейнер, то вполне разумно потребовать, чтобы содержащиеся в нем элементы имели, скажем, копирующий конструктор и не генерирующий исключений деструктор. Но надо ли требовать конструктор по умолчанию или оператор присваивания? Многие полезные типы, которые пользователи могут захотеть хранить в вашем контейнере, не имеют конструкторов по умолчанию, и если наш контейнер их использует, то такой тип не может быть использован в качестве типа элементов контейнера. Согласитесь, это не слишком обобщенно... (В качестве примера можно привести задачу 11 и се контекст из [SutterOO] (задача 2.4 в русском издании).)
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |