Int rand_int(int low, int high)
⇐ ПредыдущаяСтр 7 из 7 { static default_random_engine re {}; using Dist = uniform_int_distribution<int>; static Dist uid {}; return uid(re, Dist::param_type{low,high}); }
Эта реализация все еще требует «экспертного уровня», но использование метода rand_int() будет доступно студенту на первой неделе обучения языку С++. Просто, ради нетривиального примера, вот пример кода, который генерирует и печатает значения, распределенные по нормальному закону распределения: default_random_engine re; // движок по умолчанию normal_distribution<int> nd(31 /* мат. ожидание */,8 /* СКО */); auto norm = std::bind(nd, re); vector<int> mn(64); Int main() { for (int i = 0; i<1200; ++i) ++mn[round(norm())]; // генерация for (int i = 0; i<mn.size(); ++i) { cout << i << '\t'; for (int j=0; j<mn[i]; ++j) cout << '*'; cout << '\n'; } }
Результат выполнения: 4 * 9 * 10 *** 11 *** 12 *** 13 ***** 14 ******* 15 **** 16 ********** 17 *********** 18 **************** 19 ******************* 20 ******************* 21 ************************** 22 ********************************** 23 ********************************************** 24 ******************************************** 25 ***************************************** 26 ********************************************* 27 ********************************************************* 28 *************************************************** 29 ****************************************************************** 30 ********************************************** 31 ********************************************************************* 32 ********************************************** 33 ************************************************************* 34 ************************************************************** 35 *************************************** 36 *********************************************** 37 ********************************************** 38 ********************************************* 39 ******************************** 40 ******************************************** 41 *********************** 42 ************************** 43 ****************************** 44 ***************** 45 ************* 46 ********* 47 ******** 48 ***** 49 ***** 50 **** 51 *** 52 *** 53 ** 54 * 55 * 57 *
См. также:
Регулярные выражения
Простите, но у меня не было времени на написание этого раздела. Вернитесь к этому разделу позже.
См. также:
Концепты «Концепты» (concepts) – это механизм, описывающий требования для типов, комбинаций типов или комбинаций типов и целых чисел. Эта возможность особенно полезна для ранней проверки использования шаблонов. И наоборот, она также помогает находить ошибки в теле шаблона на ранней стадии. Давайте рассмотрим алгоритм fill из стандартной библиотеки: // типы типов template<ForwardIterator Iter, class V> // взаимоотношения между аргументами типов requires Assignable<Iter::value_type,V> // лишь объявление, а не определение void fill(Iter first, Iter last, const V& v); // Iter имеет тип int; ошибка: int не является ForwardIterator-ом // int не содержит * fill(0, 9, 9.9); // Iter имеет тип int; ok: int* является ForwardIterator-ом fill(&v[0], &v[9], 9.9);
Обратите внимание, что мы только объявили метод fill(); мы не определяли его реализацию. С другой стороны, мы точно определили, что метод fill() требует от аргументов: · Аргументы first и last должны быть типом ForwardIterator (и они должны быть одного типа). · Третий аргумент v должен быть типом, который можно присвоить типу value_type типа ForwardIterator. Конечно, мы все это знаем, ведь мы читали стандарт. Однако, компиляторы не умеют читать документы с требованиями, поэтому мы должны сказать ему в коде, в виде концептов ForwardIterator и Assignable. В результате ошибки использования метода fill() могут быть пойманы в месте использования, и текст ошибок может быть значительно яснее. Теперь у компилятора есть информация о намерениях программиста, что позволяет обеспечить хороший уровень проверок и диагностических сообщений. Концепты также помогают в реализации шаблонов. Давайте рассмотрим пример: template<ForwardIterator Iter, class V> requires Assignable<Iter::value_type,V> void fill(Iter first, Iter last, const V& v) { while (first!=last) { *first = v; // ошибка: + не определен для Forward_iterator // (нужно использовать ++first) first=first+1; } }
Эта ошибка будет отловлена сразу же, устраняя необходимость трудоемкого тестирования (хотя и не избавляет от тестирования полностью).
С возможностью классифицировать и различать разные типы типов, мы можем перегружать методы, основываясь на виде передаваемых типов. Например: // стандартный алгоритм сортировки, на основе // итераторов (с концептами): template<Random_access_iterator Iter> requires Comparable<Iter::value_type> // используем обычную реализацию void sort(Iter first, Iter last); // сортировка на основе контейнера: template<Container Cont> requires Comparable<Cont::value_type> void sort(Cont& c) { // просто вызываем версию на основе итераторов sort(c.begin(),c.end()); } void f(vector<int>& v) { sort(v.begin(), v.end()); // один способ sort(v); // еще один способ //... }
Вы можете определить свои собственные концепты, но для начала, в стандартной библиотеке определен большой набор полезных концептов, таких как ForwardIterator, Collable, LessThanComparable и Regular. Обратите внимание, стандартные библиотеки С++11 предусматривают использование концептов. См. также:
Карты концептов int* является ForwardIterator; мы сказали об этом при обсуждении концептов, и в стандартной библиотеке это всегда было именно так; даже в первой версии STL указатели использовались в качестве итераторов. Однако, мы также говорили о члене value_type типа ForwardIterator. Но int* не содержит члена с именем value_type; на самом деле, он вообще не содержит никаких членов. Так как int* может быть ForwardIterator? Поскольку мы сами это указали. С помощью concept_map мы можем сказать, что при использовании T*, где требуется ForwardIterator, мы будем рассматривать T в качестве value_type: template<Value_type T> // value_type типа T* - это T concept_map ForwardIterator<T*> { typedef T value_type; };
concept_map позволяет указать способ представления нашего типа, предотвращая от модификации существующий тип или от создания нового типа в качестве обертки. «Карты концептов» (concept maps) являются гибким и обобщенным механизмом для адаптации независимо разработанных программ для совместного использования. См. также:
Аксиомы Аксиома (axiom) – это набор предикатов, определяющих семантику концепта. Главным сценарием использование аксиом являются внешние инструменты (например, действия, нетипичные для компилятора), такие как, инструменты для предметно-ориентированных оптимизаций (domain-specific optimizations) (языки для описания программных изменений стали важным поводом появления аксиом). Аксиомы также могут быть полезны для некоторых оптимизаций (выполняемых компилятором и обычными оптимизаторами), но компиляторы не должны обращать внимания на пользовательские аксиомы; их работа основана на семантиках, определенных в стандарте. Аксиомы перечисляют пару вычислений, которые могут трактоваться как эквивалентные. Например: concept Semigroup<typename Op, typename T>: CopyConstructible<T> { T operator()(Op, T, T); axiom Associativity(Op op, T x, T y, T z) { // можно предположить, что оператор типа T является ассоциативным op(x, op(y, z)) <=> op(op(x, y), z); } } // monoid – это полугруппа с единичным элементом concept Monoid<typename Op, typename T>: Semigroup<Op, T> { T identity_element(Op); axiom Identity(Op op, T x) { op(x, identity_element(op)) <=> x; op(identity_element(op), x) <=> x; } }
<=> - это оператор эквивалентности, используемый только в аксиомах. Обратите внимание, что вы не можете (в общем случае) доказать аксиому; мы используем аксиомы для указания того, что мы не можем доказать, но что программист может назвать приемлемым допущением. Обратите внимание, что обе стороны оператора эквивалентности могут быть некорректными для некоторых значений, например использование NaN (not a number) для типов с плавающей запятой: если обе стороны эквивалентности используют NaN, то обе стороны (явно) некорректны и эквивалентны (независимо от того, что говорится в аксиоме), но если NaN используется только с одной стороны, то существует возможность получить выгоды от использования аксиомы. Аксиома это последовательность выражений эквивалентности (<=>) и условных выражений (вида “if (something) тогда мы можем предполагать следующую эквивалентность”):
// в концепте TotalOrder:
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|