Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Header <boost/operators.hpp> Documentation

Boost , ,

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Header <boost/operators.hpp>

Заголовок<boost/operators.hpp>содержит несколько наборов шаблонов классов (в пространстве имен<boost>). Эти шаблоны определяют операторов в области пространства имен с точки зрения минимального числа основных операторов, предоставляемых классом.

Contents

Rationale

Перегруженные операторы для типов классов обычно встречаются в группах. Если вы можете писать<x + y>, вы, вероятно, также хотите писать<x += y>. Если вы можете написать<x < y,>, вы также хотите<x > y, x >= y,>и<x <= y>. Кроме того, если ваш класс не имеет действительно удивительного поведения, некоторые из этих связанных операторов могут быть определены в терминах других (например,<x >= y <=> !(x < y)>). Воспроизведение этого шаблона для нескольких классов является утомительным и подверженным ошибкам. Шаблоныboost/operators.hppпомогают создавать операторы для вас в области пространства имен на основе других операторов, которые вы определили в своем классе.

Если, например, вы объявляете такой класс:

class MyInt
    : boost::operators<MyInt>
{
    bool operator<(const MyInt& x) const;
    bool operator==(const MyInt& x) const;
    MyInt& operator+=(const MyInt& x);
    MyInt& operator-=(const MyInt& x);
    MyInt& operator*=(const MyInt& x);
    MyInt& operator/=(const MyInt& x);
    MyInt& operator%=(const MyInt& x);
    MyInt& operator|=(const MyInt& x);
    MyInt& operator&=(const MyInt& x);
    MyInt& operator^=(const MyInt& x);
    MyInt& operator++();
    MyInt& operator--();
};

Затем<operators<>>шаблон добавляет более десятка дополнительных операторов, таких как<operator>>,<<=>,<>=>и<+>.Для взаимодействия с другими типами также предусмотрены двухаргументные формышаблонов.

Summary of Template Semantics

  1. Каждый шаблон оператора завершает концепцию, которую он описывает, определяя перегруженных операторов для своего целевого класса.
  2. Название шаблона класса оператора указывает на концепцию, которую будет моделировать его целевой класс.
  3. Обычно целевой класс использует в качестве базового класса инстантацию шаблона класса оператора. Некоторые шаблоны операторов поддерживаютальтернативный метод.
  4. Понятие может быть составным,т.е.оно может представлять собой общую комбинацию других, более простых понятий.
  5. Большинство шаблонов операторов требуют своего целевого класса для поддержки операций, связанных с операторами, предоставляемыми шаблоном. В соответствии с общепринятымирекомендациями по стилю кодирования, целевой класс часто требуется для предоставления оператору-партнеру назначения «основного оператора» концепции. Например,addableшаблон требуетoperator+=(T const&)и, в свою очередь, поставляетoperator+(T const&, T const&).

Use of concepts

Обсуждаемые понятия не обязательно являются стандартными библиотечными понятиями (CopyConstructible,и т. д.), хотя некоторые из них могут быть; они являются тем, что мы называемпонятиями с небольшим «c». В частности, они отличаются от предыдущих тем, что онине описывают точную семантику операторов, которые они требуют определения, за исключением требований, что (a) семантика операторов, сгруппированных в одну концепцию, должна быть последовательной (например,эффекты оценки<a += b>и<a = a + b>выражений должны быть одинаковыми), и (b) что типы возврата операторов должны следовать семантике типов возврата соответствующих операторов для встроенных типов (например,<operator<>должны возвращать тип, конвертируемый в<bool>, и<T::operator-=>должны возвращать тип, конвертируемый в<T>). Такие «свободные» требования делают библиотеку операторов применимой к более широкому набору целевых классов из разных доменов, то естьв конечном итоге более полезной.

Usage

Two-Argument Template Forms

General Considerations

Аргументы в пользу двоичного оператора обычно имеют одинаковые типы, но не редкость определить операторов, которые объединяют разные типы. Дляпримераможно умножить математический вектор на скаляр. Для этой цели поставляются двухаргументные шаблонные формы шаблонов оператора арифметики. При применении двухаргументной формы шаблона желаемый тип возврата операторов обычно определяет, какой из двух рассматриваемых типов должен быть получен из шаблона оператора. Например, если результат<T + U>имеет тип<T>, то<T>(не<U>) должен быть получен из<addable<T, U>>. Шаблоны сравнения<less_than_comparable<T, U>>,<equality_comparable<T, U>>,<equivalent<T, U>>и<partially_ordered<T, U>>являются исключениями из этого руководства, поскольку тип возврата операторов, которые они определяют, составляет<bool>.

На компиляторах, которые не поддерживают частичную специализацию, формы с двумя аргументами должны быть указаны с помощью названий, показанных ниже с отставанием<'2'>. Формы с одним аргументом с зацеплением<'1'>предусмотрены для симметрии и для обеспечения определенных применений метода цепей базового класса.

Mixed Arithmetics

Другое применение двухаргументных шаблонных форм для смешанной арифметики между типом<T>и типом<U>, который конвертируется в<T>. В этом случае есть два способа, при которых формы шаблона с двумя аргументами полезны: один - предоставить соответствующие подписи для перегрузки оператора, второй - производительность.

Что касается перегрузки оператора, предположим, что, например, что<U>является<int>, что<T>является определяемым пользователем неограниченным целым типом и что<double operator-(double, const T&)>существует. Если вы хотите вычислить<int - T>и не предоставляете<T operator-(int, const T&)>, компилятор будет считать<double operator-(double, const T&)>лучшим совпадением, чем<T operator-(const T&, const T&)>, что, вероятно, будет отличаться от намерения пользователя. Для определения полного набора подписей оператора предусмотрены дополнительные «левые» формы двухаргументных шаблонных форм<subtractable2_left<T, U>>,<dividable2_left<T, U>>,<modable2_left<T, U>>, которые определяют подписи для некоммутативных операторов, где<U>появляется с левой стороны<operator-(const U&, const T&)>,<operator/(const U&, const T&)>,<operator%(const U&, const T&)>.

Что касается производительности, обратите внимание, что при использовании одного двоичного оператора для арифметики смешанного типа аргумент типа<U>должен быть преобразован в тип<T>. Однако на практике часто встречаются более эффективные реализации, например<T::operator-=(const U&)>, которые позволяют избежать ненужных преобразований из<U>в<T>. Двухаргументные шаблонные формы арифметического оператора создают дополнительные интерфейсы оператора, которые используют эти более эффективные реализации. Тем не менее, в «левых» формах не наблюдается прироста производительности: они по-прежнему нуждаются в преобразовании из<U>в<T>и имеют реализацию, эквивалентную коду, который был бы автоматически создан компилятором, если бы он считал бинарного оператора одного типа лучшим совпадением.

Base Class Chaining and Object Size

Каждый шаблон класса оператора, за исключениемарифметических примеровипомощников итератора, имеет дополнительный, но необязательный параметр типа шаблона<B>. Этот параметр будет общедоступным базовым классом реализованного шаблона. Это означает, что это должен быть класс. Его можно использовать, чтобы избежать вздутия размеров объектов, которое обычно связано с множественным наследованием от нескольких пустых базовых классов (см. примечаниедля пользователей более старых версийдля более подробной информации). Чтобы обеспечить поддержку группы операторов, используйте параметр<B>для цепных шаблонов операторов в иерархию однобазовых классов, показанную в примере использования. Техника также используется составными шаблонами операторов для групповых определений операторов. Если цепочка становится слишком длинной для поддержки компилятора, попробуйте заменить некоторые шаблоны оператора одним сгруппированным шаблоном оператора, который связывает старые шаблоны вместе; предел длины применяется только к количеству шаблонов непосредственно в цепочке, а не к тем, которые скрыты в шаблонах группы.

Пещера:для привязки к базовому классу, которыйнешаблон оператора Boost при использованииодноаргументной формышаблона оператора Boost, необходимо указать шаблон оператора с отставанием<'1'>в его названии. В противном случае библиотека будет считать, что вы имеете в виду определение двоичной операции, объединяющей класс, который вы собираетесь использовать в качестве базового класса, и класс, который вы получаете.

Separate, Explicit Instantiation

На некоторых компиляторах (например,Borland, GCC) даже однонаследование, по-видимому, вызывает увеличение размера объекта в некоторых случаях. Если вы не определяете шаблон класса, вы можете получить лучшую производительность в размере объекта, полностью избегая вывода, и вместо этого явно инстанцируете шаблон оператора следующим образом:

    class myclass // lose the inheritance...
    {
        //...
    };
    // explicitly instantiate the operators I need.
    template struct less_than_comparable<myclass>;
    template struct equality_comparable<myclass>;
    template struct incrementable<myclass>;
    template struct decrementable<myclass>;
    template struct addable<myclass,long>;
    template struct subtractable<myclass,long>;

Обратите внимание, что некоторые шаблоны оператора не могут использовать этот обходной путь и должны быть базовым классом их основного типа операнда. Эти шаблоны определяют операторов, которые должны быть функциями-членами, а обходной путь требует, чтобы операторы были независимыми функциями-друзьями. Соответствующими шаблонами являются:

  • dereferenceable<>
  • indexable<>
  • Любой композитный шаблон оператора, который включает по меньшей мере один из вышеперечисленных шаблонов.

Как отметил Даниэль Крумл;глер, этот метод нарушает 14.6.5/2 и, таким образом, является непортативным. Обоснование заключается в том, что операторы, введенные путем инстанциации, например<less_than_comparable<myclass>>, не могут быть найдены ADL в соответствии с правилами, приведенными в пункте 3.4.2/2, поскольку мой класс не является ассоциированным классом<less_than_comparable<myclass>>. Используйте эту технику только в том случае, если все остальное не удается.

Requirement Portability

Многие компиляторы (, напримерMSVC 6.3, GCC 2.95.2) не будут обеспечивать соблюдение требований в таблицах шаблонов оператора, если фактически не используются операции, зависящие от них. Это не стандартное поведение. В частности, хотя было бы удобно вывести все ваши классы, которые нуждаются в бинарных операторах, из шаблонов<operators<>>и<operators2<>>, независимо от того, выполняют ли они все требования этих шаблонов, этот ярлык не является портативным. Даже если это в настоящее время работает с вашим компилятором, это может не сработать позже.

Example

Этот пример показывает, как некоторые изшаблонов оператора арифметикимогут использоваться с геометрическим классом точек (шаблоном).

template <class T>
class point    // note: private inheritance is OK here!
    : boost::addable< point<T>          // point + point
    , boost::subtractable< point<T>     // point - point
    , boost::dividable2< point<T>, T    // point / T
    , boost::multipliable2< point<T>, T // point * T, T * point
      > > > >
{
public:
    point(T, T);
    T x() const;
    T y() const;
    point operator+=(const point&);
    // point operator+(point, const point&) automatically
    // generated by addable.
    point operator-=(const point&);
    // point operator-(point, const point&) automatically
    // generated by subtractable.
    point operator*=(T);
    // point operator*(point, const T&) and
    // point operator*(const T&, point) auto-generated
    // by multipliable.
    point operator/=(T);
    // point operator/(point, const T&) auto-generated
    // by dividable.
private:
    T x_;
    T y_;
};
// now use the point<> class:
template <class T>
T length(const point<T> p)
{
    return sqrt(p.x()*p.x() + p.y()*p.y());
}
const point<float> right(0, 1);
const point<float> up(1, 0);
const point<float> pi_over_4 = up + right;
const point<float> pi_over_4_normalized = pi_over_4 / length(pi_over_4);

Arithmetic Operators

Шаблоны оператора арифметики облегчают задачу создания пользовательского числового типа. Учитывая основной набор операторов, шаблоны добавляют связанных операторов в числовой класс. Эти операции похожи на те, которые имеют стандартные арифметические типы, и могут включать в себя сравнения, добавление, инкрементирование, логические и битовые манипуляциии т. д.. Кроме того, поскольку большинству числовых типов требуется более одного из этих операторов, некоторые шаблоны предоставляются для объединения нескольких основных шаблонов операторов в одной декларации.

Требования к типам, используемым для создания простых шаблонов оператора, определяются с точки зрения выражений, которые должны быть действительными, и типа возврата выражения. Составные шаблоны оператора только перечисляют, какие другие шаблоны они используют. Поставляемые операции и требования составных шаблонов оператора могут быть выведены из операций и требований перечисленных компонентов.

Simple Arithmetic Operators

Эти шаблоны являются «простыми», поскольку они предоставляют операторам на основе одной операции, которую должен обеспечить базовый тип. Они имеют дополнительный параметр шаблона<B>, который не показан, для метода цепей базового класса.

Основной тип операнда<T>должен быть классового типа, встроенные типы не поддерживаются.

Simple Arithmetic Operator Template Classes
Key
<T>Основной операндный тип <U>Альтернативный тип операнда
<t>,<t1>: значения типа<T> <u>: значение типа<U>
Template Supplied Operations Requirements
<less_than_comparable<T>>
<less_than_comparable1<T>>
<bool operator>(const T&, const T&)>
<bool operator<=(const T&, const T&)>
<bool operator>=(const T&, const T&)>
<t < t1>
Возврат кабриолета в<bool>. См.Заказная записка.
<less_than_comparable<T, U>>
<less_than_comparable2<T, U>>
<bool operator<=(const T&, const U&)>
<bool operator>=(const T&, const U&)>
<bool operator>(const U&, const T&)>
<bool operator<(const U&, const T&)>
<bool operator<=(const U&, const T&)>
<bool operator>=(const U&, const T&)>
<t < u><t > u>.
Возврат кабриолета в<bool>. См.Заказная записка.
<equality_comparable<T>>
<equality_comparable1<T>>
<bool operator!=(const T&, const T&)> <t == t1>
Возврат кабриолета в<bool>.
<equality_comparable<T, U>>
<equality_comparable2<T, U>>
<bool operator==(const U&, const T&)>
<bool operator!=(const U&, const T&)>
<bool operator!=(const T&, const U&)>
<t == u>
Возврат кабриолета в<bool>.
<addable<T>>
<addable1<T>>
<T operator+(const T&, const T&)> <T temp(t); temp += t1>
Возврат кабриолета в<T>.Симметричная нота.
<addable<T, U>>
<addable2<T, U>>
<T operator+(const T&, const U&)>
<T operator+(const U&, const T& )>
<T temp(t); temp += u>
Возврат кабриолета в<T>.Симметричная нота.
<subtractable<T>>
<subtractable1<T>>
<T operator-(const T&, const T&)> <T temp(t); temp -= t1>
Возврат кабриолета в<T>.Симметричная нота.
<subtractable<T, U>>
<subtractable2<T, U>>
<T operator-(const T&, const U&)> <T temp(t); temp -= u>.
Возврат кабриолета в<T>.Симметричная нота.
<subtractable2_left<T, U>> <T operator-(const U&, const T&)> <T temp(u); temp -= t>
Возврат кабриолета в<T>.
<multipliable<T>>
<multipliable1<T>>
<T operator*(const T&, const T&)> <T temp(t); temp *= t1>
Возврат кабриолета в<T>.Симметричная нота.
<multipliable<T, U>>
<multipliable2<T, U>>
<T operator*(const T&, const U&)>
<T operator*(const U&, const T&)>
<T temp(t); temp *= u>
Возврат кабриолета в<T>.Симметричная нота.
<dividable<T>>
<dividable1<T>>
<T operator/(const T&, const T&)> <T temp(t); temp /= t1>
Возврат кабриолета в<T>.Симметричная нота.
<dividable<T, U>>
<dividable2<T, U>>
<T operator/(const T&, const U&)> <T temp(t); temp /= u>
Возврат кабриолета в<T>. См. симметричную ноту.
<dividable2_left<T, U>> <T operator/(const U&, const T&)> <T temp(u); temp /= t>.
Возврат кабриолета в<T>.
<modable<T>>
<modable1<T>>
<T operator%(const T&, const T&)> <T temp(t); temp %= t1>
Возврат кабриолета в<T>. См. примечание к симметрии.
<modable<T, U>>
<modable2<T, U>>
<T operator%(const T&, const U&)> <T temp(t); temp %= u>
Возврат кабриолета в<T>. См. примечание к симметрии.
<modable2_left<T, U>> <T operator%(const U&, const T&)> <T temp(u); temp %= t>
Возврат кабриолета в<T>.
<orable<T>>
<orable1<T>>
<T operator|(const T&, const T&)> <T temp(t); temp |= t1>.
Возврат кабриолета в<T>.Симметричная нота.
<orable<T, U>>
<orable2<T, U>>
<T operator|(const T&, const U&)>
<T operator|(const U&, const T&)>
<T temp(t); temp |= u>
Возврат кабриолета в<T>.Симметричная нота.
<andable<T>>
<andable1<T>>
<T operator&(const T&, const T&)> <T temp(t); temp &= t1>.
Возврат кабриолета в<T>.Симметричная нота.
<andable<T, U>>
<andable2<T, U>>
<T operator&(const T&, const U&)>
<T operator&(const U&, const T&)>
<T temp(t); temp &= u>
Возврат кабриолета в<T>.Симметричная нота.
<xorable<T>>
<xorable1<T>>
<T operator^(const T&, const T&)> <T temp(t); temp ^= t1>.
Возврат кабриолета в<T>.Симметричная нота.
<xorable<T, U>>
<xorable2<T, U>>
<T operator^(const T&, const U&)>
<T operator^(const U&, const T&)>
<T temp(t); temp ^= u>
Возврат кабриолета в<T>.Симметричная нота.
<incrementable<T>> <T operator++(T&, int)> <T temp(t); ++t>
Возврат кабриолета в<T>.
<decrementable<T>> <T operator--(T&, int)> <T temp(t); --t;>
Возврат кабриолета в<T>.
<left_shiftable<T>>
<left_shiftable1<T>>
<T operator<<(const T&, const T&)> <T temp(t); temp <<= t1>.
Возврат кабриолета в<T>.Симметричная нота.
<left_shiftable<T, U>>
<left_shiftable2<T, U>>
<T operator<<(const T&, const U&)> <T temp(t); temp <<= u>
Возврат кабриолета в<T>.Симметричная нота.
<right_shiftable<T>>
<right_shiftable1<T>>
<T operator>>(const T&, const T&)> <T temp(t); temp >>= t1>
Возврат кабриолета в<T>. См. примечание к симметрии.
<right_shiftable<T, U>>
<right_shiftable2<T, U>>
<T operator>>(const T&, const U&)> <T temp(t); temp >>= u>
Возврат кабриолета в<T>. См. примечание к симметрии.
<equivalent<T>>
<equivalent1<T>>
<bool operator==(const T&, const T&)> <t < t1>
Возврат кабриолета в<bool>. См.Заказная записка.
<equivalent<T, U>>
<equivalent2<T, U>>
<bool operator==(const T&, const U&)> <t < u><t > u>.
Возврат кабриолета в<bool>. См.Заказная записка.
<partially_ordered<T>>
<partially_ordered1<T>>
<bool operator>(const T&, const T&)>
<bool operator<=(const T&, const T&)>
<bool operator>=(const T&, const T&)>
<t < t1><t == t1>.
Возврат кабриолета в<bool>. См.Заказная записка.
<partially_ordered<T, U>>
<partially_ordered2<T, U>>
<bool operator<=(const T&, const U&)>
<bool operator>=(const T&, const U&)>
<bool operator>(const U&, const T&)>
<bool operator<(const U&, const T&)>
<bool operator<=(const U&, const T&)>
<bool operator>=(const U&, const T&)>
<t < u><t > u><t == u>
Возврат кабриолета в<bool>. См.Заказная записка.

Ordering Note

Шаблоны<less_than_comparable<T>>и<partially_ordered<T>>обеспечивают одинаковый набор операций. Однако в работах<less_than_comparable<T>>предполагается, что все значения типа<T>могут быть размещены в общем порядке. Если это не соответствует действительности, напримерЗначения не-а-числа в арифметике IEEE с плавающей точкой, то<partially_ordered<T>>следует использовать. Шаблон<partially_ordered<T>>может использоваться для полностью упорядоченного типа, но он не так эффективен, как<less_than_comparable<T>>. Это правило также применяется для<less_than_comparable<T, U>>и<partially_ordered<T, U>>в отношении упорядочения всех<T>и<U>значений, а также для обеих версий<equivalent<>>. Решение для<equivalent<>>заключается в написании пользовательского<operator==>для целевого класса.

Symmetry Note

Прежде чем говорить о симметрии, нужно поговорить об оптимизации, чтобы понять причины различных стилей реализации операторов. Давайте рассмотрим<operator+>для класса<T>в качестве примера:

T operator+( const T& lhs, const T& rhs )
{
   return T( lhs ) += rhs;
}
This would be a normal implementation of operator+, but it is not an efficient one. An unnamed local copy of lhs is created, operator+= is called on it and it is copied to the function return value (which is another unnamed object of type T). The standard doesn't generally allow the intermediate object to be optimized away:
3.7.2/2: Automatic storage duration

If a named automatic object has initialization or a destructor with side effects, it shall not be destroyed before the end of its block, nor shall it be eliminated as an optimization even if it appears to be unused, except that a class object or its copy may be eliminated as specified in 12.8.
The reference to 12.8 is important for us:
12.8/15: Copying class objects
...
For a function with a class return type, if the expression in the return statement is the name of a local object, and the cv-unqualified type of the local object is the same as the function return type, an implementation is permitted to omit creating the temporary object to hold the function return value, even if the class copy constructor or destructor has side effects.
This optimization is known as the named return value optimization (NRVO), which leads us to the following implementation for operator+:
T operator+( const T& lhs, const T& rhs )
{
   T nrv( lhs );
   nrv += rhs;
   return nrv;
}
Given this implementation, the compiler is allowed to remove the intermediate object. Sadly, not all compiler implement the NRVO, some even implement it in an incorrect way which makes it useless here. Without the NRVO, the NRVO-friendly code is no worse than the original code showed above, but there is another possible implementation, which has some very special properties:
T operator+( T lhs, const T& rhs )
{
   return lhs += rhs;
}
The difference to the first implementation is that lhs is not taken as a constant reference used to create a copy; instead, lhs is a by-value parameter, thus it is already the copy needed. This allows another optimization (12.2/2) for some cases. Consider a + b + c where the result of a + b is not copied when used as lhs when adding c. This is more efficient than the original code, but not as efficient as a compiler using the NRVO. For most people, it is still preferable for compilers that don't implement the NRVO, but the operator+ now has a different function signature. Also, the number of objects created differs for (a + b ) + c and a + ( b + c ). Most probably, this won't be a problem for you, but if your code relies on the function signature or a strict symmetric behaviour, you should set BOOST_FORCE_SYMMETRIC_OPERATORS in your user-config. This will force the NRVO-friendly implementation to be used even for compilers that don't implement the NRVO.

Grouped Arithmetic Operators

Следующие шаблоны предоставляют общие группы связанных операций. Например, так как тип, который можно добавить, обычно также является субподрядным, шаблон<additive>предоставляет объединенные операторы обоих. Сгруппированные шаблоны операторов имеют дополнительный параметр шаблона<B>, который не показан, для метода цепей базового класса.

Grouped Arithmetic Operator Template Classes
Key
<T>Основной операндный тип <U>Альтернативный тип операнда
Template Component Operator Templates
<totally_ordered<T>>
<totally_ordered1<T>>
  • < [83] >
  • < [85] >
less_than_comparable<T>
  • equality_comparable<T>
  • [ORIG_END] -->
    <totally_ordered<T, U>>
    <totally_ordered2<T, U>>
    • < [89] >
    • < [91] >
    less_than_comparable<T, U>
  • equality_comparable<T, U>
  • [ORIG_END] -->
    <additive<T>>
    <additive1<T>>
    • < [95] >
    • < [97] >
    addable<T>
  • subtractable<T>
  • [ORIG_END] -->
    <additive<T, U>>
    <additive2<T, U>>
    • < [101] >
    • < [103] >
    addable<T, U>
  • subtractable<T, U>
  • [ORIG_END] -->
    <multiplicative<T>>
    <multiplicative1<T>>
    • < [107] >
    • < [109] >
    multipliable<T>
  • dividable<T>
  • [ORIG_END] -->
    <multiplicative<T, U>>
    <multiplicative2<T, U>>
    • < [113] >
    • < [115] >
    multipliable<T, U>
  • dividable<T, U>
  • [ORIG_END] -->
    <integer_multiplicative<T>>
    <integer_multiplicative1<T>>
    • < [119] >
    • < [121] >
    multiplicative<T>
  • modable<T>
  • [ORIG_END] -->
    <integer_multiplicative<T, U>>
    <integer_multiplicative2<T, U>>
    • < [125] >
    • < [127] >
    multiplicative<T, U>
  • modable<T, U>
  • [ORIG_END] -->
    <arithmetic<T>>
    <arithmetic1<T>>
    • < [131] >
    • < [119] >
    additive<T>
  • multiplicative<T>
  • [ORIG_END] -->
    <arithmetic<T, U>>
    <arithmetic2<T, U>>
    • < [137] >
    • < [125] >
    additive<T, U>
  • multiplicative<T, U>
  • [ORIG_END] -->
    <integer_arithmetic<T>>
    <integer_arithmetic1<T>>
    • < [131] >
    • < [145] >
    additive<T>
  • integer_multiplicative<T>
  • [ORIG_END] -->
    <integer_arithmetic<T, U>>
    <integer_arithmetic2<T, U>>
    • < [137] >
    • < [151] >
    additive<T, U>
  • integer_multiplicative<T, U>
  • [ORIG_END] -->
    <bitwise<T>>
    <bitwise1<T>>
    • < [155] >
    • < [157] >
    • < [159] >
    xorable<T>
  • andable<T>
  • orable<T>
  • [ORIG_END] -->
    <bitwise<T, U>>
    <bitwise2<T, U>>
    • < [164] >
    • < [166] >
    • < [168] >
    xorable<T, U>
  • andable<T, U>
  • orable<T, U>
  • [ORIG_END] -->
    <unit_steppable<T>>
    • < [173] >
    • < [175] >
    incrementable<T>
  • decrementable<T>
  • [ORIG_END] -->
    <shiftable<T>>
    <shiftable1<T>>
    • < [179] >
    • < [181] >
    left_shiftable<T>
  • right_shiftable<T>
  • [ORIG_END] -->
    <shiftable<T, U>>
    <shiftable2<T, U>>
    • < [185] >
    • < [187] >
    left_shiftable<T, U>
  • right_shiftable<T, U>
  • [ORIG_END] -->
    <ring_operators<T>>
    <ring_operators1<T>>
    • < [131] >
    • < [107] >
    additive<T>
  • multipliable<T>
  • [ORIG_END] -->
    <ring_operators<T, U>>
    <ring_operators2<T, U>>
    • < [137] >
    • < [199] >
    • < [113] >
    additive<T, U>
  • subtractable2_left<T, U>
  • multipliable<T, U>
  • [ORIG_END] -->
    <ordered_ring_operators<T>>
    <ordered_ring_operators1<T>>
    • < [206] >
    • < [208] >
    ring_operators<T>
  • totally_ordered<T>
  • [ORIG_END] -->
    <ordered_ring_operators<T, U>>
    <ordered_ring_operators2<T, U>>
    • < [212] >
    • < [214] >
    ring_operators<T, U>
  • totally_ordered<T, U>
  • [ORIG_END] -->
    <field_operators<T>>
    <field_operators1<T>>
    • < [206] >
    • < [109] >
    ring_operators<T>
  • dividable<T>
  • [ORIG_END] -->
    <field_operators<T, U>>
    <field_operators2<T, U>>
    • < [212] >
    • < [115] >
    • < [228] >
    ring_operators<T, U>
  • dividable<T, U>
  • dividable2_left<T, U>
  • [ORIG_END] -->
    <ordered_field_operators<T>>
    <ordered_field_operators1<T>>
    • < [233] >
    • < [208] >
    field_operators<T>
  • totally_ordered<T>
  • [ORIG_END] -->
    <ordered_field_operators<T, U>>
    <ordered_field_operators2<T, U>>
    • < [239] >
    • < [214] >
    field_operators<T, U>
  • totally_ordered<T, U>
  • [ORIG_END] -->
    <euclidean_ring_operators<T>>
    <euclidean_ring_operators1<T>>
    • < [206] >
    • < [109] >
    • < [121] >
    ring_operators<T>
  • dividable<T>
  • modable<T>
  • [ORIG_END] -->
    <euclidean_ring_operators<T, U>>
    <euclidean_ring_operators2<T, U>>
    • < [212] >
    • < [115] >
    • < [228] >
    • < [127] >
    • < [262] >
    ring_operators<T, U>
  • dividable<T, U>
  • dividable2_left<T, U>
  • modable<T, U>
  • modable2_left<T, U>
  • [ORIG_END] -->
    <ordered_euclidean_ring_operators<T>>
    <ordered_euclidean_ring_operators1<T>>
    • < [269] >
    • < [208] >
    euclidean_ring_operators<T>
  • totally_ordered<T>
  • [ORIG_END] -->
    <ordered_euclidean_ring_operators<T, U>>
    <ordered_euclidean_ring_operators2<T, U>>
    • < [275] >
    • < [214] >
    euclidean_ring_operators<T, U>
  • totally_ordered<T, U>
  • [ORIG_END] -->

    Spelling: euclidean vs. euclidian

    Старые версии Boost. Библиотека операторов использовала "<euclidian>", но было указано, что "<euclidean>" является более распространенным правописанием. Чтобы быть совместимой со старой версией, библиотека теперь поддерживает оба написания.

    Example Templates

    Шаблоны классов арифметических операторов<operators<>>и<operators2<>>являются примерами классов групп нерасширяемых операторов. Эти шаблоны унаследованных классов из предыдущих версий заголовка не могут быть использованы дляцепей базового класса.

    Final Arithmetic Operator Template Classes
    Key
    <T>Основной операндный тип <U>Альтернативный тип операнда
    Template Component Operator Templates
    <operators<T>>
    • < [208] >
    • < [283] >
    • < [285] >
    • < [287] >
    totally_ordered<T>
  • integer_arithmetic<T>
  • bitwise<T>
  • unit_steppable<T>
  • [ORIG_END] -->
    <operators<T, U>>
    <operators2<T, U>>
    • < [214] >
    • < [295] >
    • < [297] >
    totally_ordered<T, U>
  • integer_arithmetic<T, U>
  • bitwise<T, U>
  • [ORIG_END] -->

    Arithmetic Operators Demonstration and Test Program

    Программаoperators_test.cppдемонстрирует использование шаблонов арифметических операторов, а также может быть использована для проверки правильности работы. Проверьте отчет о состоянии компилятора для результатов тестирования на выбранных платформах.

    Dereference Operators and Iterator Helpers

    Помощник итераторашаблонов облегчает задачу создания пользовательского итератора. Подобно арифметическим типам, полный итератор имеет множество операторов, которые являются «избыточными» и могут быть реализованы с точки зрения основного набора операторов.

    Операторыdereferenceбыли мотивированы помощникамиитератора, но часто полезны и в контекстах, не связанных с итератором. Многие из резервных операторов итератора также являются арифметическими операторами, поэтому классы помощников итератора заимствуют многие из операторов, определенных выше. На самом деле, только два новых оператора должны быть определены (указатель к члену<operator->>и подстрочный<operator[]>)!

    Требования к типам, используемым для инстанцирования операторов отсчета, определяются с точки зрения выражений, которые должны быть действительными, и типа их возврата. Составные шаблоны оператора перечисляют свои шаблоны компонентов, которые должен поддерживать и, возможно, другие требования.

    Dereference Operators

    Все шаблоны оператора отсчета в этой таблице принимают необязательный параметр шаблона (не показан), который используется дляцепей базового класса.

    Dereference Operator Template Classes
    Key
    <T>Тип операнда <P>:<pointer>Тип
    <D>:<difference_type> <R>:<reference>Тип
    <i>: объект типа<T>(итератор) <n>: объект типа<D>(индекс)
    Template Supplied Operations Requirements
    <dereferenceable<T, P>> <P operator->() const> <(&*i)>. Возврат кабриолета в<P>.
    <indexable<T, D, R>> <R operator[](D n) const> <*(i + n)>. Возвращение типа<R>.

    Grouped Iterator Operators

    Существует пять шаблонов оператора итератора, каждый для разных категорий итераторов. В следующей таблице показаны группы операторов для любой категории, которую может определить пользовательский итератор. Эти шаблоны классов имеют дополнительный дополнительный параметр шаблона<B>, который не показан, для поддержки цепей базового класса.

    Iterator Operator Class Templates
    Key
    <T>Тип операнда <P>:<pointer>Тип
    <D>:<difference_type> <R>:<reference>Тип
    <V>:<value_type>
    Template Component Operator Templates
    <input_iteratable<T, P>>
    • < [85] >
    • < [173] >
    • < [306] >
    equality_comparable<T>
  • incrementable<T>
  • dereferenceable<T, P>
  • [ORIG_END] -->
    <output_iteratable<T>>
    • < [173] >
    incrementable<T> [ORIG_END] -->
    <forward_iteratable<T, P>>
    • < [314] >
    input_iteratable<T, P> [ORIG_END] -->
    <bidirectional_iteratable<T, P>>
    • < [317] >
    • < [175] >
    forward_iteratable<T, P>
  • decrementable<T>
  • [ORIG_END] -->
    <random_access_iteratable<T, P, D, R>>
    • < [323] >
    • < [208] >
    • < [327] >
    • < [329] >
    bidirectional_iteratable<T, P>
  • totally_ordered<T>
  • additive<T, D>
  • indexable<T, D, R>
  • [ORIG_END] -->

    Iterator Helpers

    Существует также пять шаблонов класса помощников итератора, каждый из которых соответствует отдельной категории итератора. Эти классы не могут быть использованы для цепей базового класса. Следующие резюме показывают, что эти шаблоны классов предоставляют как операторы итератора из шаблоновитератора оператора класса, так и шаблоны типа итератора, требуемые стандартом C++<iterator_category>,<value_type>,и т. Д..

    Iterator Helper Class Templates
    Key
    <T>Тип операнда <P>:<pointer>Тип
    <D>:<difference_type> <R>:<reference>Тип
    <V>:<value_type> <x1, x2>: объекты типа<T>
    Template Operations & Requirements
    <input_iterator_helper<T, V, D, P, R>> Поддерживает операции и имеет требования
    • < [314] >
    input_iteratable<T, P> [ORIG_END] -->
    <output_iterator_helper<T>> Поддерживает операции и имеет требования
    • < [338] >
    См. также1,2.output_iteratable<T> See also [1], [2]. [ORIG_END] -->
    <forward_iterator_helper<T, V, D, P, R>> Поддерживает операции и имеет требования
    • < [317] >
    forward_iteratable<T, P> [ORIG_END] -->
    <bidirectional_iterator_helper<T, V, D, P, R>> Поддерживает операции и имеет требования
    • < [323] >
    bidirectional_iteratable<T, P> [ORIG_END] -->
    <random_access_iterator_helper<T, V, D, P, R>> Поддерживает операции и имеет требования
    • < [347] >
    Для удовлетворенияRandomAccessIterator,<x1 - x2>с возвратным конвертируемым в<D>также требуется.random_access_iteratable<T, P, D, R> To satisfy RandomAccessIterator, x1 - x2 with return convertible to D is also required. [ORIG_END] -->

    Iterator Helper Notes

    В отличие от других шаблонов помощников итератора,<output_iterator_helper>принимает только один параметр шаблона — тип его целевого класса. Хотя для некоторых это может показаться ненужным ограничением, стандарт требует, чтобы<difference_type>и<value_type>любого итератора вывода были<void>(24.3.1 [lib.iterator.traits]), и<output_iterator_helper>шаблон соблюдает это требование. Кроме того, выходные итераторы в стандарте имеют пустотные<pointer>и<reference>типы, поэтому<output_iterator_helper>делает то же самое.

    Поскольку самопрокси является наиболее простым и распространенным способом реализации выходных итераторов (см., например, вставку [24.4.2] и потоковые итераторы [24.5] в стандартной библиотеке),<output_iterator_helper>поддерживает идиому, определяя<operator*>и<operator++>функции-члены, которые просто возвращают неконстантную ссылку на сам итератор. Поддержка самостоятельного прокси-сервера позволяет во многих случаях свести задачу написания выходного итератора к написанию всего двух членских функций — соответствующего конструктора и оператора копирования. Например, вот возможная реализация<boost::function_output_iterator>адаптера:

    template<class UnaryFunction>
    struct function_output_iterator
        : boost::output_iterator_helper< function_output_iterator<UnaryFunction> >
    {
        explicit function_output_iterator(UnaryFunction const& f = UnaryFunction())
            : func(f) {}
        template<typename T>
        function_output_iterator& operator=(T const& value)
        {
            this->func(value);
            return *this;
        }
     private:
        UnaryFunction func;
    };
    

    Обратите внимание, что поддержка самостоятельного прокси-сервера не мешает вам использовать<output_iterator_helper>для облегчения реализации любого другого, другого типа итератора вывода. Если целевой тип<output_iterator_helper>дает свое собственное определение<operator*>или<operator++>, то эти операторы будут использоваться, а те, которые поставляются<output_iterator_helper>, никогда не будут реализованы.

    Iterator Demonstration and Test Program

    Программаiterators_test.cppдемонстрирует использование шаблонов итератора, а также может использоваться для проверки правильности работы. Ниже приведен пользовательский итератор, определенный в программе тестирования. Он демонстрирует правильную (хотя и тривиальную) реализацию основных операций, которые должны быть определены для того, чтобы помощники итератора «заполнили» остальные операции итератора.

    template <class T, class R, class P>
    struct test_iter
      : public boost::random_access_iterator_helper<
         test_iter<T,R,P>, T, std::ptrdiff_t, P, R>
    {
      typedef test_iter self;
      typedef R Reference;
      typedef std::ptrdiff_t Distance;
    public:
      explicit test_iter(T* i =0);
      test_iter(const self& x);
      self& operator=(const self& x);
      Reference operator*() const;
      self& operator++();
      self& operator--();
      self& operator+=(Distance n);
      self& operator-=(Distance n);
      bool operator==(const self& x) const;
      bool operator<(const self& x) const;
      friend Distance operator-(const self& x, const self& y);
    };
    

    Проверьте отчет о состоянии компиляторадля результатов испытаний с выбранными платформами.


    Contributors

    Dave Abrahams
    Started the library and contributed the arithmetic operators in boost/operators.hpp.
    Jeremy Siek
    Contributed the dereference operators and iterator helpers in boost/operators.hpp. Also contributed iterators_test.cpp.
    Aleksey Gurtovoy
    Contributed the code to support base class chaining while remaining backward-compatible with old versions of the library.
    Beman Dawes
    Contributed operators_test.cpp.
    Daryle Walker
    Contributed classes for the shift operators, equivalence, partial ordering, and arithmetic conversions. Added the grouped operator classes. Added helper classes for input and output iterators.
    Helmut Zeisel
    Contributed the 'left' operators and added some grouped operator classes.
    Daniel Frey
    Contributed the NRVO-friendly and symmetric implementation of arithmetic operators.

    Note for Users of Older Versions

    Измененияв интерфейсе библиотеки и рекомендуемое использованиебыли мотивированы некоторыми практическими проблемами, описанными ниже. Новая версия библиотеки по-прежнему обратно совместима с предыдущей (так что вы невынужденыизменять какой-либо существующий код), но старое использование обесценено. Хотя это было, возможно, проще и интуитивно понятнее, чем использование цепей базовых классов, было обнаружено, что старая практика получения из нескольких шаблонов операторов может привести к тому, что полученные классы будут намного больше, чем они должны быть. Большинство современных компиляторов C++ значительно раздувают размер классов, полученных из нескольких пустых базовых классов, хотя сами базовые классы не имеют состояния. Например, размер<point<int>>из примеравыше составлял 12-24 байта на различных компиляторах платформы Win32, вместо ожидаемых 8 байтов.

    Строго говоря, это не было ошибкой библиотеки - языковые правила позволяют компилятору применять оптимизацию пустого базового класса в этой ситуации. В принципе произвольное число пустых базовых классов может быть распределено при том же смещении при условии, что ни один из них не имеет общего предка (см. пункт 5 раздела 10.5 стандарта). Но определение языка также не требуетреализациидля оптимизации, и лишь немногие из сегодняшних компиляторов реализуют его, когда речь идет о множественном наследовании. Что еще хуже, очень маловероятно, что реализаторы примут его в качестве будущего улучшения существующих компиляторов, потому что это нарушит бинарную совместимость между кодом, генерируемым двумя различными версиями одного и того же компилятора. Как сказал Мэтт Остерн: «Один из немногих случаев, когда у вас есть свобода делать такие вещи, это когда вы ориентируетесь на новую архитектуру». С другой стороны, многие распространенные компиляторы будут использовать оптимизацию пустой базы для отдельных иерархий наследования.

    Учитывая важность проблемы для пользователей библиотеки (которая направлена на то, чтобы быть полезной для написания легких классов, таких как<MyInt>или<point<>>), и силы, описанные выше, мы решили изменить интерфейс библиотеки так, чтобы раздувание размера объекта можно было устранить даже на компиляторах, которые поддерживают только простейшую форму оптимизации пустого базового класса. Современный библиотечный интерфейс является результатом этих изменений. Хотя новое использование немного сложнее старого, мы считаем, что стоит сделать библиотеку более полезной в реальном мире. Алексей Гуртовой внес код, который поддерживает новую идиому использования, позволяя библиотеке оставаться обратно совместимой.


    Пересмотрено: 7 августа 2008

    Copyright © Beman Dawes, David Abrahams, 1999-2001.

    Copyright © Daniel Frey, 2002-2009.

    Использование, модификация и распространение подчиняются Boost Software Лицензия, версия 1.0. (См. сопроводительный файл LICENSE_1_0.txt or copy at www.boost.org/LICENSE_1_0.txt)[ORIG_END] -->

    Статья Header <boost/operators.hpp> Documentation раздела может быть полезна для разработчиков на c++ и boost.




    Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



    :: Главная :: ::


    реклама


    ©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
    Top.Mail.Ru

    Время компиляции файла: 2024-08-30 11:47:00
    2025-05-19 16:30:52/0.03899884223938/1