From 4755b42909b10fd95fd9394cc434c489bb84d3e2 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 4 Nov 2002 01:59:32 +0000 Subject: [PATCH] Daniel Frey's NRVO patches [SVN r16084] --- include/boost/operators.hpp | 265 ++- operators.htm | 3121 ++++++++++++++++++++++------------- 2 files changed, 2060 insertions(+), 1326 deletions(-) diff --git a/include/boost/operators.hpp b/include/boost/operators.hpp index bd571ec..3ade8ba 100644 --- a/include/boost/operators.hpp +++ b/include/boost/operators.hpp @@ -9,6 +9,9 @@ // See http://www.boost.org for most recent version including documentation. // Revision History +// 21 Oct 02 Modified implementation of operators to allow compilers with a +// correct named return value optimization (NRVO) to produce optimal +// code. (Daniel Frey) // 02 Dec 01 Bug fixed in random_access_iteratable. (Helmut Zeisel) // 28 Sep 01 Factored out iterator operator groups. (Daryle Walker) // 27 Aug 01 'left' form for non commutative operators added; @@ -149,127 +152,107 @@ struct equality_comparable1 : B friend bool operator!=(const T& x, const T& y) { return !(x == y); } }; -template -struct multipliable2 : B -{ - friend T operator*(T x, const U& y) { return x *= y; } - friend T operator*(const U& y, T x) { return x *= y; } +// NRVO-friendly implementation (contributed by Daniel Frey) ---------------// + +#if defined(BOOST_HAS_NRVO) || defined(BOOST_FORCE_SYMMETRIC_OPERATORS) + +// This is the optimal implementation for ISO/ANSI C++, +// but it requires the compiler to implement the NRVO. +// If the compiler has no NRVO, this is the best symmetric +// implementation available. + +#define BOOST_BINARY_OPERATOR_COMMUTATIVE( NAME, OP ) \ +template \ +struct NAME##2 : B \ +{ \ + friend T operator OP( const T& lhs, const U& rhs ) \ + { T nrv( lhs ); nrv OP##= rhs; return nrv; } \ + friend T operator OP( const U& lhs, const T& rhs ) \ + { T nrv( rhs ); nrv OP##= lhs; return nrv; } \ +}; \ + \ +template \ +struct NAME##1 : B \ +{ \ + friend T operator OP( const T& lhs, const T& rhs ) \ + { T nrv( lhs ); nrv OP##= rhs; return nrv; } \ }; -template -struct multipliable1 : B -{ - friend T operator*(T x, const T& y) { return x *= y; } +#define BOOST_BINARY_OPERATOR_NON_COMMUTATIVE( NAME, OP ) \ +template \ +struct NAME##2 : B \ +{ \ + friend T operator OP( const T& lhs, const U& rhs ) \ + { T nrv( lhs ); nrv OP##= rhs; return nrv; } \ +}; \ + \ +template \ +struct NAME##2_left : B \ +{ \ + friend T operator OP( const U& lhs, const T& rhs ) \ + { T nrv( lhs ); nrv OP##= rhs; return nrv; } \ +}; \ + \ +template \ +struct NAME##1 : B \ +{ \ + friend T operator OP( const T& lhs, const T& rhs ) \ + { T nrv( lhs ); nrv OP##= rhs; return nrv; } \ }; -template -struct addable2 : B -{ - friend T operator+(T x, const U& y) { return x += y; } - friend T operator+(const U& y, T x) { return x += y; } +#else // defined(BOOST_HAS_NRVO) || defined(BOOST_FORCE_SYMMETRIC_OPERATORS) + +// For compilers without NRVO the following code is optimal, but not symmetric! +// Note that the implementation of NAME##2_left only looks cool, but doesn't +// provide optimization opportunities to the compiler :) + +#define BOOST_BINARY_OPERATOR_COMMUTATIVE( NAME, OP ) \ +template \ +struct NAME##2 : B \ +{ \ + friend T operator OP( T lhs, const U& rhs ) { return lhs OP##= rhs; } \ + friend T operator OP( const U& lhs, T rhs ) { return rhs OP##= lhs; } \ +}; \ + \ +template \ +struct NAME##1 : B \ +{ \ + friend T operator OP( T lhs, const T& rhs ) { return lhs OP##= rhs; } \ }; -template -struct addable1 : B -{ - friend T operator+(T x, const T& y) { return x += y; } +#define BOOST_BINARY_OPERATOR_NON_COMMUTATIVE( NAME, OP ) \ +template \ +struct NAME##2 : B \ +{ \ + friend T operator OP( T lhs, const U& rhs ) { return lhs OP##= rhs; } \ +}; \ + \ +template \ +struct NAME##2_left : B \ +{ \ + friend T operator OP( const U& lhs, const T& rhs ) \ + { return T( lhs ) OP##= rhs; } \ +}; \ + \ +template \ +struct NAME##1 : B \ +{ \ + friend T operator OP( T lhs, const T& rhs ) { return lhs OP##= rhs; } \ }; -template -struct subtractable2 : B -{ - friend T operator-(T x, const U& y) { return x -= y; } -}; +#endif // defined(BOOST_HAS_NRVO) || defined(BOOST_FORCE_SYMMETRIC_OPERATORS) -template -struct subtractable2_left : B -{ - friend T operator-(const U& x, const T& y) - { T result(x); return result -= y; } -}; +BOOST_BINARY_OPERATOR_COMMUTATIVE( multipliable, * ); +BOOST_BINARY_OPERATOR_COMMUTATIVE( addable, + ); +BOOST_BINARY_OPERATOR_NON_COMMUTATIVE( subtractable, - ); +BOOST_BINARY_OPERATOR_NON_COMMUTATIVE( dividable, / ); +BOOST_BINARY_OPERATOR_NON_COMMUTATIVE( modable, % ); +BOOST_BINARY_OPERATOR_COMMUTATIVE( xorable, ^ ); +BOOST_BINARY_OPERATOR_COMMUTATIVE( andable, & ); +BOOST_BINARY_OPERATOR_COMMUTATIVE( orable, | ); -template -struct subtractable1 : B -{ - friend T operator-(T x, const T& y) { return x -= y; } -}; - -template -struct dividable2 : B -{ - friend T operator/(T x, const U& y) { return x /= y; } -}; - -template -struct dividable2_left : B -{ - friend T operator/(const U& x, const T& y) - { T result(x); return result /= y; } -}; - -template -struct dividable1 : B -{ - friend T operator/(T x, const T& y) { return x /= y; } -}; - -template -struct modable2 : B -{ - friend T operator%(T x, const U& y) { return x %= y; } -}; - -template -struct modable2_left : B -{ - friend T operator%(const U& x, const T& y) - { T result(x); return result %= y; } -}; - -template -struct modable1 : B -{ - friend T operator%(T x, const T& y) { return x %= y; } -}; - -template -struct xorable2 : B -{ - friend T operator^(T x, const U& y) { return x ^= y; } - friend T operator^(const U& y, T x) { return x ^= y; } -}; - -template -struct xorable1 : B -{ - friend T operator^(T x, const T& y) { return x ^= y; } -}; - -template -struct andable2 : B -{ - friend T operator&(T x, const U& y) { return x &= y; } - friend T operator&(const U& y, T x) { return x &= y; } -}; - -template -struct andable1 : B -{ - friend T operator&(T x, const T& y) { return x &= y; } -}; - -template -struct orable2 : B -{ - friend T operator|(T x, const U& y) { return x |= y; } - friend T operator|(const U& y, T x) { return x |= y; } -}; - -template -struct orable1 : B -{ - friend T operator|(T x, const T& y) { return x |= y; } -}; +#undef BOOST_BINARY_OPERATOR_COMMUTATIVE +#undef BOOST_BINARY_OPERATOR_NON_COMMUTATIVE // incrementable and decrementable contributed by Jeremy Siek @@ -278,9 +261,9 @@ struct incrementable : B { friend T operator++(T& x, int) { - incrementable_type tmp(x); + incrementable_type nrv(x); ++x; - return tmp; + return nrv; } private: // The use of this typedef works around a Borland bug typedef T incrementable_type; @@ -291,9 +274,9 @@ struct decrementable : B { friend T operator--(T& x, int) { - decrementable_type tmp(x); + decrementable_type nrv(x); --x; - return tmp; + return nrv; } private: // The use of this typedef works around a Borland bug typedef T decrementable_type; @@ -320,30 +303,46 @@ struct indexable : B }; // More operator classes (contributed by Daryle Walker) --------------------// +// (NRVO-friendly implementation contributed by Daniel Frey) ---------------// -template -struct left_shiftable2 : B -{ - friend T operator<<(T x, const U& y) { return x <<= y; } +#if defined(BOOST_HAS_NRVO) + +#define BOOST_BINARY_OPERATOR( NAME, OP ) \ +template \ +struct NAME##2 : B \ +{ \ + friend T operator OP( const T& lhs, const U& rhs ) \ + { T nrv( lhs ); nrv OP##= rhs; return nrv; } \ +}; \ + \ +template \ +struct NAME##1 : B \ +{ \ + friend T operator OP( const T& lhs, const T& rhs ) \ + { T nrv( lhs ); nrv OP##= rhs; return nrv; } \ }; -template -struct left_shiftable1 : B -{ - friend T operator<<(T x, const T& y) { return x <<= y; } +#else // defined(BOOST_HAS_NRVO) + +#define BOOST_BINARY_OPERATOR( NAME, OP ) \ +template \ +struct NAME##2 : B \ +{ \ + friend T operator OP( T lhs, const U& rhs ) { return lhs OP##= rhs; } \ +}; \ + \ +template \ +struct NAME##1 : B \ +{ \ + friend T operator OP( T lhs, const T& rhs ) { return lhs OP##= rhs; } \ }; -template -struct right_shiftable2 : B -{ - friend T operator>>(T x, const U& y) { return x >>= y; } -}; +#endif // defined(BOOST_HAS_NRVO) -template -struct right_shiftable1 : B -{ - friend T operator>>(T x, const T& y) { return x >>= y; } -}; +BOOST_BINARY_OPERATOR( left_shiftable, << ); +BOOST_BINARY_OPERATOR( right_shiftable, >> ); + +#undef BOOST_BINARY_OPERATOR template struct equivalent2 : B diff --git a/operators.htm b/operators.htm index 11699d9..07a8754 100644 --- a/operators.htm +++ b/operators.htm @@ -1,92 +1,135 @@ + + + + - - -Header <boost/operators.hpp> Documentation - + Header <boost/operators.hpp> Documentation + - + +

c++boost.gif (8819 bytes)Header <boost/operators.hpp>

-

c++boost.gif (8819 bytes)Header <boost/operators.hpp>

+

The header <boost/operators.hpp> supplies + several sets of class templates (in namespace boost). These + templates define operators at namespace scope in terms of a minimal + number of fundamental operators provided by the class.

-

The header <boost/operators.hpp> -supplies several sets of class templates (in namespace -boost). These templates define operators at namespace -scope in terms of a minimal number of fundamental operators -provided by the class.

+

Contents

-

Contents

+ + +

Rationale

+ +

Overloaded operators for class types typically occur in groups. If you + can write x + y, you probably also want to be able + to write x += y. If you can write x < y, you + also want x > y, x >= y, and x <= y. + Moreover, unless your class has really surprising behavior, some of these + related operators can be defined in terms of others (e.g. x >= y + <=> !(x < y)). Replicating this boilerplate for multiple + classes is both tedious and error-prone. The boost/operators.hpp templates help + by generating operators for you at namespace scope based on other + operators you've defined in your class.

+ +

If, for example, you declare a class like this:

+ +
+
+class MyInt
     : boost::operators<MyInt>
 {
     bool operator<(const MyInt& x) const; 
@@ -101,170 +144,175 @@ on other operators you've defined in your class.

MyInt& operator^=(const MyInt& x); MyInt& operator++(); MyInt& operator--(); -};
-
+}; + + -

then the operators<> -template adds more than a dozen additional operators, such as -operator>, <=, >=, and -(binary) +. Two-argument forms of -the templates are also provided to allow interaction with other types.

+

then the operators<> + template adds more than a dozen additional operators, such as + operator>, <=, >=, and + (binary) +. Two-argument forms of the + templates are also provided to allow interaction with other types.

-

Summary of Template Semantics

+

Summary of Template Semantics

-
    -
  1. Each operator template completes the concept(s) it describes by - defining overloaded operators for its target class.
  2. +
      +
    1. Each operator template completes the concept(s) it describes by + defining overloaded operators for its target class.
    2. -
    3. The name of an operator class template indicates the concept that its target class will - model.
    4. +
    5. The name of an operator class template indicates the concept that its target class will model.
    6. -
    7. Usually, the target class uses an instantation of the operator class - template as a base class. Some operator templates support an - alternate method.
    8. +
    9. Usually, the target class uses an instantation of the operator + class template as a base class. Some operator templates support an alternate method.
    10. -
    11. The concept can be compound, i.e. it may represent a - common combination of other, simpler concepts.
    12. +
    13. The concept can be compound, i.e. it may represent a common + combination of other, simpler concepts.
    14. -
    15. Most operator templates require their target class to support - operations related to the operators supplied by the template. In - accordance with widely accepted coding style - recommendations, the target class is often required to - supply the assignment counterpart operator of the concept's - "main operator." For example, the addable - template requires operator+=(T const&) and - in turn supplies operator+(T const&, T - const&).
    16. -
    +
  3. Most operator templates require their target class to support + operations related to the operators supplied by the template. In + accordance with widely accepted coding style recommendations, the + target class is often required to supply the assignment counterpart + operator of the concept's "main operator." For example, the + addable template requires operator+=(T + const&) and in turn supplies operator+(T const&, T + const&).
  4. +
-

Use of concepts

+

Use of concepts

-

The discussed concepts are not necessarily the standard library's -concepts (CopyConstructible, etc.), although some of them could -be; they are what we call concepts with a small 'c'. In -particular, they are different from the former ones in that they do -not describe precise semantics of the operators they require to -be defined, except the requirements that (a) the semantics of the -operators grouped in one concept should be consistent (e.g. -effects of evaluating of a += b and a = a + b -expressions should be the same), and (b) that the return types of the -operators should follow semantics of return types of corresponding -operators for built-in types (e.g. operator< -should return a type convertible to bool, and -T::operator-= should return type convertible to -T). Such "loose" requirements make operators -library applicable to broader set of target classes from different -domains, i.e. eventually more useful.

+

The discussed concepts are not necessarily the standard library's + concepts (CopyConstructible, etc.), although some of them could + be; they are what we call concepts with a small 'c'. In + particular, they are different from the former ones in that they do + not describe precise semantics of the operators they require to be + defined, except the requirements that (a) the semantics of the operators + grouped in one concept should be consistent (e.g. effects of + evaluating of a += b and + a = a + b expressions should be the + same), and (b) that the return types of the operators should follow + semantics of return types of corresponding operators for built-in types + (e.g. operator< should return a type convertible + to bool, and T::operator-= should return type + convertible to T). Such "loose" requirements make operators + library applicable to broader set of target classes from different + domains, i.e. eventually more useful.

-

Usage

+

Usage

-

Two-Argument Template Forms

+

Two-Argument Template Forms

-

General Considerations

+

General Considerations

-

The arguments to a binary operator commonly have identical types, but -it is not unusual to want to define operators which combine different -types. For example, one might want to multiply a -mathematical vector by a scalar. The two-argument template forms of the -arithmetic operator templates are supplied for this purpose. When -applying the two-argument form of a template, the desired return type of -the operators typically determines which of the two types in question -should be derived from the operator template. For example, if the -result of T + U is of type T, then -T (not U) should be derived from addable<T, U>. The comparison -templates (less_than_comparable<T, -U>, equality_comparable<T, -U>, equivalent<T, U>, -and partially_ordered<T, U>) -are exceptions to this guideline, since the return type of the operators -they define is bool.

+

The arguments to a binary operator commonly have identical types, but + it is not unusual to want to define operators which combine different + types. For example, one might want to multiply a + mathematical vector by a scalar. The two-argument template forms of the + arithmetic operator templates are supplied for this purpose. When + applying the two-argument form of a template, the desired return type of + the operators typically determines which of the two types in question + should be derived from the operator template. For example, if the result + of T + U is of type T, then + T (not U) should be derived from addable<T, U>. The comparison templates + (less_than_comparable<T, + U>, equality_comparable<T, U>, + equivalent<T, U>, and + partially_ordered<T, + U>) are exceptions to this guideline, since the return type + of the operators they define is bool.

-

On compilers which do not support partial specialization, the -two-argument forms must be specified by using the names shown below with -the trailing '2'. The single-argument forms with the -trailing '1' are provided for symmetry and to enable -certain applications of the base class chaining -technique.

+

On compilers which do not support partial specialization, the + two-argument forms must be specified by using the names shown below with + the trailing '2'. The single-argument forms with the + trailing '1' are provided for symmetry and to enable certain + applications of the base class chaining + technique.

-

Mixed Arithmetics

+

Mixed Arithmetics

-

Another application of the two-argument template forms is for -mixed arithmetics between a type T and a type U -that is convertible to T. In this case there are two ways -where the two-argument template forms are helpful: one is to provide -the respective signatures for operator overloading, the second is -performance.

+

Another application of the two-argument template forms is for mixed + arithmetics between a type T and a type U that + is convertible to T. In this case there are two ways where + the two-argument template forms are helpful: one is to provide the + respective signatures for operator overloading, the second is + performance.

-

With respect to the operator overloading assume e.g. that -U is int, that T is an user-defined -unlimited integer type, and that double operator-(double, const -T&) exists. If one wants to compute int - T and -does not provide T operator-(int, const T&), the -compiler will consider double operator-(double, const T&) -to be a better match than T operator-(const T&, const -T&), which will probably be different from the user's intention. -To define a complete set of operator signatures, additional 'left' forms -of the two-argument template forms are provided (subtractable2_left<T, U>, -dividable2_left<T, U>, -modable2_left<T, U>) that -define the signatures for non-commutative operators where U -appears on the left hand side (operator-(const U&, const -T&), operator/(const U&, const T&), -operator%(const U&, const T&)).

+

With respect to the operator overloading assume e.g. that + U is int, that T is an + user-defined unlimited integer type, and that double + operator-(double, const T&) exists. If one wants to compute + int - T and does not provide T operator-(int, const + T&), the compiler will consider double operator-(double, + const T&) to be a better match than T operator-(const + T&, const T&), which will probably be different from the + user's intention. To define a complete set of operator signatures, + additional 'left' forms of the two-argument template forms are provided + (subtractable2_left<T, + U>, dividable2_left<T, + U>, modable2_left<T, + U>) that define the signatures for non-commutative + operators where U appears on the left hand side + (operator-(const U&, const T&), + operator/(const U&, const T&), operator%(const + U&, const T&)).

-

With respect to the performance observe that when one uses the -single type binary operator for mixed type arithmetics, the type -U argument has to be converted to type T. In -practice, however, there are often more efficient implementations of, -say T::operator-=(const U&) that avoid unnecessary -conversions from U to T. The two-argument -template forms of the arithmetic operator create additional operator -interfaces that use these more efficient implementations. There is, however, -no performance gain in the 'left' forms: they still need a conversion -from U to T and have an implementation -equivalent to the code that would be automatically created by the compiler -if it considered the single type binary operator to be the best match.

+

With respect to the performance observe that when one uses the single + type binary operator for mixed type arithmetics, the type U + argument has to be converted to type T. In practice, + however, there are often more efficient implementations of, say + T::operator-=(const U&) that avoid unnecessary + conversions from U to T. The two-argument + template forms of the arithmetic operator create additional operator + interfaces that use these more efficient implementations. There is, + however, no performance gain in the 'left' forms: they still need a + conversion from U to T and have an + implementation equivalent to the code that would be automatically created + by the compiler if it considered the single type binary operator to be + the best match.

-

Base Class Chaining and Object Size

+

Base Class Chaining and Object Size

-

Every operator class template, except the arithmetic -examples and the iterator helpers, has an -additional, but optional, template type parameter B. This -parameter will be a publicly-derived base class of the instantiated template. -This means it must be a class type. It can be used to avoid the bloating of -object sizes that is commonly associated with multiple-inheritance from -several empty base classes (see the note for users of -older versions for more details). To provide support for a group of -operators, use the B parameter to chain operator templates -into a single-base class hierarchy, demostrated in the usage -example. The technique is also used by the composite operator templates -to group operator definitions. If a chain becomes too long for the compiler to -support, try replacing some of the operator templates with a single grouped -operator template that chains the old templates together; the length limit only -applies to the number of templates directly in the chain, not those hidden in -group templates.

+

Every operator class template, except the arithmetic examples and the iterator + helpers, has an additional, but optional, template type parameter + B. This parameter will be a publicly-derived base class of + the instantiated template. This means it must be a class type. It can be + used to avoid the bloating of object sizes that is commonly associated + with multiple-inheritance from several empty base classes (see the note for users of older versions for more + details). To provide support for a group of operators, use the + B parameter to chain operator templates into a single-base + class hierarchy, demostrated in the usage example. + The technique is also used by the composite operator templates to group + operator definitions. If a chain becomes too long for the compiler to + support, try replacing some of the operator templates with a single + grouped operator template that chains the old templates together; the + length limit only applies to the number of templates directly in the + chain, not those hidden in group templates.

-

Caveat: to chain to a base class which is -not a Boost operator template when using the single-argument form of a Boost operator template, -you must specify the operator template with the trailing -'1' in its name. Otherwise the library will assume you -mean to define a binary operation combining the class you intend to use -as a base class and the class you're deriving.

+

Caveat: to chain to a base class which is + not a Boost operator template when using the single-argument form of a Boost operator template, you + must specify the operator template with the trailing '1' in + its name. Otherwise the library will assume you mean to define a binary + operation combining the class you intend to use as a base class and the + class you're deriving.

-

Separate, Explicit Instantiation

+

Separate, Explicit + Instantiation

-

On some compilers (e.g. Borland, GCC) even single-inheritance seems -to cause an increase in object size in some cases. If you are not defining -a class template, you may get better object-size performance by avoiding -derivation altogether, and instead explicitly instantiating the operator -template as follows:

+

On some compilers (e.g. Borland, GCC) even single-inheritance + seems to cause an increase in object size in some cases. If you are not + defining a class template, you may get better object-size performance by + avoiding derivation altogether, and instead explicitly instantiating the + operator template as follows:

-
+    
+
     class myclass // lose the inheritance...
     {
         //...
@@ -277,38 +325,43 @@ template as follows:

template struct decrementable<myclass>; template struct addable<myclass,long>; template struct subtractable<myclass,long>; -
+
+
-

Note that some operator templates cannot use this workaround and must -be a base class of their primary operand type. Those templates define -operators which must be member functions, and the workaround needs the -operators to be independent friend functions. The relevant templates are:

+

Note that some operator templates cannot use this workaround and must + be a base class of their primary operand type. Those templates define + operators which must be member functions, and the workaround needs the + operators to be independent friend functions. The relevant templates + are:

- +
    +
  • dereferenceable<>
  • -

    Requirement Portability

    +
  • indexable<>
  • -

    Many compilers (e.g. MSVC 6.3, GCC 2.95.2) will not enforce -the requirements in the operator template tables unless the operations -which depend on them are actually used. This is not standard-conforming -behavior. In particular, although it would be convenient to derive all -your classes which need binary operators from the -operators<> -and operators2<> -templates, regardless of whether they implement all the requirements -of those templates, this shortcut is not portable. Even if this currently -works with your compiler, it may not work later.

    +
  • Any composite operator template that includes at least one of the + above
  • +
-

Example

+

Requirement Portability

-

This example shows how some of the arithmetic -operator templates can be used with a geometric point class (template).

+

Many compilers (e.g. MSVC 6.3, GCC 2.95.2) will not enforce the + requirements in the operator template tables unless the operations which + depend on them are actually used. This is not standard-conforming + behavior. In particular, although it would be convenient to derive all + your classes which need binary operators from the operators<> and operators2<> templates, regardless of + whether they implement all the requirements of those templates, this + shortcut is not portable. Even if this currently works with your + compiler, it may not work later.

+

Example

+ +

This example shows how some of the arithmetic + operator templates can be used with a geometric point class + (template).

 template <class T>
 class point    // note: private inheritance is OK here!
@@ -358,880 +411,1544 @@ const point<float> pi_over_4 = up + right;
 const point<float> pi_over_4_normalized = pi_over_4 / length(pi_over_4);
 
-

Arithmetic Operators

+

Arithmetic Operators

-

The arithmetic operator templates ease the task of creating a custom -numeric type. Given a core set of operators, the templates add related -operators to the numeric class. These operations are like the ones the -standard arithmetic types have, and may include comparisons, adding, -incrementing, logical and bitwise manipulations, etc. Further, since -most numeric types need more than one of these operators, some -templates are provided to combine several of the basic operator -templates in one declaration.

+

The arithmetic operator templates ease the task of creating a custom + numeric type. Given a core set of operators, the templates add related + operators to the numeric class. These operations are like the ones the + standard arithmetic types have, and may include comparisons, adding, + incrementing, logical and bitwise manipulations, etc. Further, + since most numeric types need more than one of these operators, some + templates are provided to combine several of the basic operator templates + in one declaration.

-

The requirements for the types used to instantiate the simple operator -templates are specified in terms of expressions which must be valid and -the expression's return type. The composite operator templates only list -what other templates they use. The supplied operations and requirements -of the composite operator templates can be inferred from the operations and -requirements of the listed components.

+

The requirements for the types used to instantiate the simple operator + templates are specified in terms of expressions which must be valid and + the expression's return type. The composite operator templates only list + what other templates they use. The supplied operations and requirements + of the composite operator templates can be inferred from the operations + and requirements of the listed components.

-

Simple Arithmetic Operators

+

Simple Arithmetic Operators

-

These templates are "simple" since they provide operators -based on a single operation the base type has to provide. They have an -additional optional template parameter B, which is not shown, -for the base class chaining technique. +

These templates are "simple" since they provide operators based on a + single operation the base type has to provide. They have an additional + optional template parameter B, which is not shown, for the + base class chaining technique.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Simple Arithmetic Operator Template Classes
- - - - - - - - - -
Key
T: primary operand typeU: alternate operand type
t, t1: values of type - Tu: value of type U
TemplateSupplied OperationsRequirements
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.
- Return convertible to bool. See the Ordering Note.
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.
- Returns convertible to bool. See the Ordering Note.
equality_comparable<T>
- equality_comparable1<T>
bool operator!=(const T&, const T&)t == t1.
- Return convertible to bool.
equality_comparable<T, U>
- equality_comparable2<T, U>
friend bool operator==(const U&, const T&)
- friend bool operator!=(const U&, const T&)
- friend bool operator!=( const T&, const U&)
t == u.
- Return convertible to bool.
addable<T>
- addable1<T>
T operator+(T, const T&)t += t1.
- Return convertible to T.
addable<T, U>
- addable2<T, U>
T operator+(T, const U&)
- T operator+(const U&, T )
t += u.
- Return convertible to T.
subtractable<T>
- subtractable1<T>
T operator-(T, const T&)t -= t1.
- Return convertible to T.
subtractable<T, U>
- subtractable2<T, U>
T operator-(T, const U&)t -= u.
- Return convertible to T.
subtractable2_left<T, U>T operator-(const U&, const T&)T temp(u); temp -= t.
- Return convertible to T.
multipliable<T>
- multipliable1<T>
T operator*(T, const T&)t *= t1.
- Return convertible to T.
multipliable<T, U>
- multipliable2<T, U>
T operator*(T, const U&)
- T operator*(const U&, T )
t *= u.
- Return convertible to T.
dividable<T>
- dividable1<T>
T operator/(T, const T&)t /= t1.
- Return convertible to T.
dividable<T, U>
- dividable2<T, U>
T operator/(T, const U&)t /= u.
- Return convertible to T.
dividable2_left<T, U>T operator/(const U&, const T&)T temp(u); temp /= t.
- Return convertible to T.
modable<T>
- modable1<T>
T operator%(T, const T&)t %= t1.
- Return convertible to T.
modable<T, U>
- modable2<T, U>
T operator%(T, const U&)t %= u.
- Return convertible to T.
modable2_left<T, U>T operator%(const U&, const T&)T temp(u); temp %= t.
- Return convertible to T.
orable<T>
- orable1<T>
T operator|(T, const T&)t |= t1.
- Return convertible to T.
orable<T, U>
- orable2<T, U>
T operator|(T, const U&)
- T operator|(const U&, T )
t |= u.
- Return convertible to T.
andable<T>
- andable1<T>
T operator&(T, const T&)t &= t1.
- Return convertible to T.
andable<T, U>
- andable2<T, U>
T operator&(T, const U&)
- T operator&(const U&, T)
t &= u.
- Return convertible to T.
xorable<T>
- xorable1<T>
T operator^(T, const T&)t ^= t1.
- Return convertible to T.
xorable<T, U>
- xorable2<T, U>
T operator^(T, const U&)
- T operator^(const U&, T )
t ^= u.
- Return convertible to T.
incrementable<T>T operator++(T& x, int)T temp(x); ++x; return temp;
- Return convertible to T.
decrementable<T>T operator--(T& x, int)T temp(x); --x; return temp;
- Return convertible to T.
left_shiftable<T>
- left_shiftable1<T>
T operator<<(T, const T&)t <<= t1.
- Return convertible to T.
left_shiftable<T, U>
- left_shiftable2<T, U>
T operator<<(T, const U&)t <<= u.
- Return convertible to T.
right_shiftable<T>
- right_shiftable1<T>
T operator>>(T, const T&)t >>= t1.
- Return convertible to T.
right_shiftable<T, U>
- right_shiftable2<T, U>
T operator>>(T, const U&)t >>= u.
- Return convertible to T.
equivalent<T>
- equivalent1<T>
bool operator==(const T&, const T&)t < t1.
- Return convertible to bool. See the Ordering Note.
equivalent<T, U>
- equivalent2<T, U>
bool operator==(const T&, const U&)t < u. t > u.
- Returns convertible to bool. See the Ordering Note.
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.
- Returns convertible to bool. See the Ordering Note.
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.
- Returns convertible to bool. See the Ordering Note.
+ + -

Ordering Note

+ + - - - - - - - - - - - - - -
+ Simple Arithmetic Operator Template Classes +
+ + -

The less_than_comparable<T> -and partially_ordered<T> -templates provide the same set of operations. However, the workings of -less_than_comparable<T> -assume that all values of type T can be placed in a total order. If -that is not true (e.g. Not-a-Number values in IEEE floating point -arithmetic), then -partially_ordered<T> -should be used. The -partially_ordered<T> -template can be used for a totally-ordered type, but it is not as efficient as -less_than_comparable<T>. -This rule also applies for -less_than_comparable<T, -U> and partially_ordered<T, -U> with respect to the ordering of all T and -U values, and for both versions of -equivalent<>. The solution for -equivalent<> is to write a -custom operator== for the target class.

+ + -

Grouped Arithmetic Operators

+ + -

The following templates provide common groups of related operations. -For example, since a type which is addable is usually also subractable, the -additive template provides the combined -operators of both. The grouped operator templates have an additional -optional template parameter B, which is not shown, for the -base class chaining technique.

+ + -
+ Key +
T: primary operand typeU: alternate operand type
t, t1: values of type + T
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Grouped Arithmetic Operator Template Classes
- - - - - -
Key
T: primary operand typeU: alternate operand type
TemplateComponent Operator Templates
totally_ordered<T>
- totally_ordered1<T>
totally_ordered<T, U>
- totally_ordered2<T, U>
additive<T>
- additive1<T>
additive<T, U>
- additive2<T, U>
multiplicative<T>
- multiplicative1<T>
multiplicative<T, U>
- multiplicative2<T, U>
integer_multiplicative<T>
- integer_multiplicative1<T>
integer_multiplicative<T, U>
- integer_multiplicative2<T, U>
arithmetic<T>
- arithmetic1<T>
arithmetic<T, U>
- arithmetic2<T, U>
integer_arithmetic<T>
- integer_arithmetic1<T>
integer_arithmetic<T, U>
- integer_arithmetic2<T, U>
bitwise<T>
- bitwise1<T>
bitwise<T, U>
- bitwise2<T, U>
unit_steppable<T>
shiftable<T>
- shiftable1<T>
shiftable<T, U>
- shiftable2<T, U>
ring_operators<T>
- ring_operators1<T>
ring_operators<T, U>
- ring_operators2<T, U>
ordered_ring_operators<T>
- ordered_ring_operators1<T>
ordered_ring_operators<T, U>
- ordered_ring_operators2<T, U>
field_operators<T>
- field_operators1<T>
field_operators<T, U>
- field_operators2<T, U>
ordered_field_operators<T>
- ordered_field_operators1<T>
ordered_field_operators<T, U>
- ordered_field_operators2<T, U>
euclidian_ring_operators<T>
- euclidian_ring_operators1<T>
euclidian_ring_operators<T, U>
- euclidian_ring_operators2<T, U>
ordered_euclidian_ring_operators<T>
- ordered_euclidian_ring_operators1<T>
ordered_euclidian_ring_operators<T, U>
- ordered_euclidian_ring_operators2<T, U>
- -

Example Templates

- -

The arithmetic operator class templates operators<> and operators2<> are examples of -non-extensible operator grouping classes. These legacy class templates, -from previous versions of the header, cannot be used for -base class chaining.

- - - - - - - - - - - - - - - - - - -
Final Arithmetic Operator Template Classes
- - - - - -
Key
T: primary operand typeU: alternate operand type
TemplateComponent Operator Templates
operators<T>
operators<T, U>
- operators2<T, U>
- -

Arithmetic Operators Demonstration and Test Program

- -

The operators_test.cpp -program demonstrates the use of the arithmetic operator templates, and -can also be used to verify correct operation. Check the compiler status report for the test results -with selected platforms.

- -

Dereference Operators and Iterator Helpers

- -

The iterator helper templates ease the task -of creating a custom iterator. Similar to arithmetic types, a complete -iterator has many operators that are "redundant" and can be -implemented in terms of the core set of operators.

- -

The dereference operators were motivated -by the iterator helpers, but are often useful in -non-iterator contexts as well. Many of the redundant iterator operators -are also arithmetic operators, so the iterator helper classes borrow -many of the operators defined above. In fact, only two new operators -need to be defined (the pointer-to-member operator-> and -the subscript operator[])!

- -

The requirements for the types used to instantiate the dereference -operators are specified in terms of expressions which must be valid and -their return type. The composite operator templates list their component -templates, which the instantiating type must support, and possibly other -requirements.

- -

Dereference Operators

- -

All the dereference operator templates in this table accept an -optional template parameter (not shown) to be used for base class chaining.

- - - - - - - - - - - - - - - - - - - - - -
Dereference Operator Template Classes
- - - - - - - - - - - - - -
Key
T: operand typeP: pointer type
D: difference_typeR: reference type
i: object of type T (an iterator)n: object of type D (an index)
TemplateSupplied OperationsRequirements
dereferenceable<T, P>P operator->() const(&*i). Return convertible to P.
indexable<T, D, R>R operator[](D n) const*(i + n). Return of type R.
- -

Grouped Iterator Operators

- -

There are five iterator operator class templates, each for a different -category of iterator. The following table shows the operator groups -for any category that a custom iterator could define. These class -templates have an additional optional template parameter B, -which is not shown, to support base class chaining.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Iterator Operator Class Templates
- - - - - - - - - - - - - -
Key
T: operand typeP: pointer type
D: difference_typeR: reference type
V: value_type
TemplateComponent Operator Templates
input_iteratable<T, P>
output_iteratable<T>
forward_iteratable<T, P>
bidirectional_iteratable<T, P>
random_access_iteratable<T, P, D, R>
- -

Iterator Helpers

- -

There are also five iterator helper class templates, each corresponding -to a different iterator category. These classes cannot be used for base class chaining. The following summaries -show that these class templates supply both the iterator operators from -the iterator operator class templates and -the iterator typedef's required by the C++ standard (iterator_category, -value_type, etc.).

- - - - - - - - - - - - - - - - - + +
Iterator Helper Class Templates
- - - - - - - - - - - - - -
Key
T: operand typeP: pointer type
D: difference_typeR: reference type
V: value_typex1, x2: objects of type T
TemplateOperations & Requirements
input_iterator_helper<T, V, D, P, R>Supports the operations and has the requirements of -
output_iterator_helper<T>Supports the operations and has the requirements of - - See also [1], [2]. + u: value of type U
forward_iterator_helper<T, V, D, P, R>Supports the operations and has the requirements of -
bidirectional_iterator_helper<T, V, D, P, R>Supports the operations and has the requirements of -
random_access_iterator_helper<T, V, D, P, R>Supports the operations and has the requirements of - - To satisfy RandomAccessIterator, - x1 - x2 with return convertible to D - is also required.
+ -

Iterator Helper Notes

+ + Template -

[1] Unlike other iterator helpers templates, -output_iterator_helper takes only one template parameter - the type of -its target class. Although to some it might seem like an unnecessary -restriction, the standard requires difference_type and -value_type of any output iterator to be -void (24.3.1 [lib.iterator.traits]), and -output_iterator_helper template respects this -requirement. Also, output iterators in the standard have void pointer and -reference types, so the output_iterator_helper does the -same. + Supplied Operations -

[2] As self-proxying is the easiest and most common way to -implement output iterators (see, for example, insert [24.4.2] and stream -iterators [24.5] in the standard library), output_iterator_helper -supports the idiom by defining operator* -and operator++ member functions which just return a -non-const reference to the iterator itself. Support for -self-proxying allows us, in many cases, to reduce the task of writing an output -iterator to writing just two member functions - an appropriate -constructor and a copy-assignment operator. For example, here is a possible -implementation of boost::function_output_iterator -adaptor:

+ 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.
+ Return convertible to bool. See the Ordering Note. + + + + 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.
+ Returns convertible to bool. See the Ordering Note. + + + + equality_comparable<T>
+ equality_comparable1<T> + + bool operator!=(const T&, const T&) + + t == t1.
+ Return convertible to 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.
+ Return convertible to bool. + + + + addable<T>
+ addable1<T> + + T operator+(const T&, const T&) + + T temp(t); temp += t1.
+ Return convertible to T. See the Symmetry Note. + + + + addable<T, U>
+ addable2<T, U> + + T operator+(const T&, const U&)
+ T operator+(const U&, const T& ) + + T temp(t); temp += u.
+ Return convertible to T. See the Symmetry Note. + + + + subtractable<T>
+ subtractable1<T> + + T operator-(const T&, const T&) + + T temp(t); temp -= t1.
+ Return convertible to T. See the Symmetry Note. + + + + subtractable<T, + U>
+ subtractable2<T, U> + + T operator-(const T&, const U&) + + T temp(t); temp -= u.
+ Return convertible to T. See the Symmetry Note. + + + + subtractable2_left<T, + U> + + T operator-(const U&, const T&) + + T temp(u); temp -= t.
+ Return convertible to T. + + + + multipliable<T>
+ multipliable1<T> + + T operator*(const T&, const T&) + + T temp(t); temp *= t1.
+ Return convertible to T. See the Symmetry Note. + + + + multipliable<T, + U>
+ multipliable2<T, U> + + T operator*(const T&, const U&)
+ T operator*(const U&, const T&) + + T temp(t); temp *= u.
+ Return convertible to T. See the Symmetry Note. + + + + dividable<T>
+ dividable1<T> + + T operator/(const T&, const T&) + + T temp(t); temp /= t1.
+ Return convertible to T. See the Symmetry Note. + + + + dividable<T, U>
+ dividable2<T, U> + + T operator/(const T&, const U&) + + T temp(t); temp /= u.
+ Return convertible to T. See the Symmetry Note. + + + + dividable2_left<T, + U> + + T operator/(const U&, const T&) + + T temp(u); temp /= t.
+ Return convertible to T. + + + + modable<T>
+ modable1<T> + + T operator%(const T&, const T&) + + T temp(t); temp %= t1.
+ Return convertible to T. See the Symmetry Note. + + + + modable<T, U>
+ modable2<T, U> + + T operator%(const T&, const U&) + + T temp(t); temp %= u.
+ Return convertible to T. See the Symmetry Note. + + + + modable2_left<T, + U> + + T operator%(const U&, const T&) + + T temp(u); temp %= t.
+ Return convertible to T. + + + + orable<T>
+ orable1<T> + + T operator|(const T&, const T&) + + T temp(t); temp |= t1.
+ Return convertible to T. See the Symmetry Note. + + + + orable<T, U>
+ orable2<T, U> + + T operator|(const T&, const U&)
+ T operator|(const U&, const T&) + + T temp(t); temp |= u.
+ Return convertible to T. See the Symmetry Note. + + + + andable<T>
+ andable1<T> + + T operator&(const T&, const T&) + + T temp(t); temp &= t1.
+ Return convertible to T. See the Symmetry Note. + + + + andable<T, U>
+ andable2<T, U> + + T operator&(const T&, const U&)
+ T operator&(const U&, const T&) + + T temp(t); temp &= u.
+ Return convertible to T. See the Symmetry Note. + + + + xorable<T>
+ xorable1<T> + + T operator^(const T&, const T&) + + T temp(t); temp ^= t1.
+ Return convertible to T. See the Symmetry Note. + + + + xorable<T, U>
+ xorable2<T, U> + + T operator^(const T&, const U&)
+ T operator^(const U&, const T&) + + T temp(t); temp ^= u.
+ Return convertible to T. See the Symmetry Note. + + + + incrementable<T> + + T operator++(T&, int) + + T temp(t); ++t
+ Return convertible to T. + + + + decrementable<T> + + T operator--(T&, int) + + T temp(t); --t;
+ Return convertible to T. + + + + left_shiftable<T>
+ left_shiftable1<T> + + T operator<<(const T&, const T&) + + T temp(t); temp <<= t1.
+ Return convertible to T. See the Symmetry Note. + + + + left_shiftable<T, + U>
+ left_shiftable2<T, U> + + T operator<<(const T&, const U&) + + T temp(t); temp <<= u.
+ Return convertible to T. See the Symmetry Note. + + + + right_shiftable<T>
+ right_shiftable1<T> + + T operator>>(const T&, const T&) + + T temp(t); temp >>= t1.
+ Return convertible to T. See the Symmetry Note. + + + + right_shiftable<T, + U>
+ right_shiftable2<T, U> + + T operator>>(const T&, const U&) + + T temp(t); temp >>= u.
+ Return convertible to T. See the Symmetry Note. + + + + equivalent<T>
+ equivalent1<T> + + bool operator==(const T&, const T&) + + t < t1.
+ Return convertible to bool. See the Ordering Note. + + + + equivalent<T, U>
+ equivalent2<T, U> + + bool operator==(const T&, const U&) + + t < u. t > u.
+ Returns convertible to bool. See the Ordering Note. + + + + 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.
+ Returns convertible to bool. See the Ordering Note. + + + + 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.
+ Returns convertible to bool. See the Ordering Note. + + + +

Ordering Note

+ +

The less_than_comparable<T> and + partially_ordered<T> + templates provide the same set of operations. However, the workings of + less_than_comparable<T> assume + that all values of type T can be placed in a total order. If + that is not true (e.g. Not-a-Number values in IEEE floating point + arithmetic), then partially_ordered<T> should be + used. The partially_ordered<T> template can + be used for a totally-ordered type, but it is not as efficient as + less_than_comparable<T>. This + rule also applies for less_than_comparable<T, U> and + partially_ordered<T, + U> with respect to the ordering of all T and + U values, and for both versions of equivalent<>. The solution for equivalent<> is to write a custom + operator== for the target class.

+ +

Symmetry Note

+ +

Before talking about symmetry, we need to talk about optimizations to + understand the reasons for the different implementation styles of + operators. Let's have a look at operator+ for a class + T as an example:

+
+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

+ +

The following templates provide common groups of related operations. + For example, since a type which is addable is usually also subractable, + the additive template provides the + combined operators of both. The grouped operator templates have an + additional optional template parameter B, which is not + shown, for the base class chaining technique.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Grouped Arithmetic Operator Template Classes +
+ + + + + + + + +
+ Key +
T: primary operand typeU: alternate operand type
+
TemplateComponent Operator Templates
totally_ordered<T>
+ totally_ordered1<T>
+ +
totally_ordered<T, + U>
+ totally_ordered2<T, U>
+ +
additive<T>
+ additive1<T>
+ +
additive<T, U>
+ additive2<T, U>
+ +
multiplicative<T>
+ multiplicative1<T>
+ +
multiplicative<T, + U>
+ multiplicative2<T, U>
+ +
integer_multiplicative<T>
+ + integer_multiplicative1<T>
+ +
integer_multiplicative<T, + U>
+ integer_multiplicative2<T, U>
+ +
arithmetic<T>
+ arithmetic1<T>
+ +
arithmetic<T, U>
+ arithmetic2<T, U>
+ +
integer_arithmetic<T>
+ integer_arithmetic1<T>
+ +
integer_arithmetic<T, + U>
+ integer_arithmetic2<T, U>
+ +
bitwise<T>
+ bitwise1<T>
+ +
bitwise<T, U>
+ bitwise2<T, U>
+ +
unit_steppable<T> + +
shiftable<T>
+ shiftable1<T>
+ +
shiftable<T, U>
+ shiftable2<T, U>
+ +
ring_operators<T>
+ ring_operators1<T>
+ +
ring_operators<T, + U>
+ ring_operators2<T, U>
+ +
ordered_ring_operators<T>
+ + ordered_ring_operators1<T>
+ +
ordered_ring_operators<T, + U>
+ ordered_ring_operators2<T, U>
+ +
field_operators<T>
+ field_operators1<T>
+ +
field_operators<T, + U>
+ field_operators2<T, U>
+ +
ordered_field_operators<T>
+ + ordered_field_operators1<T>
+ +
ordered_field_operators<T, + U>
+ ordered_field_operators2<T, U>
+ +
euclidian_ring_operators<T>
+ + euclidian_ring_operators1<T>
+ +
euclidian_ring_operators<T, + U>
+ euclidian_ring_operators2<T, U>
+ +
ordered_euclidian_ring_operators<T>
+ + ordered_euclidian_ring_operators1<T>
+ +
ordered_euclidian_ring_operators<T, + U>
+ ordered_euclidian_ring_operators2<T, U>
+ +
+ +

Example Templates

+ +

The arithmetic operator class templates operators<> and operators2<> are examples of + non-extensible operator grouping classes. These legacy class templates, + from previous versions of the header, cannot be used for base class chaining.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ Final Arithmetic Operator Template Classes +
+ + + + + + + + +
+ Key +
T: primary operand typeU: alternate operand type
+
TemplateComponent Operator Templates
operators<T> + +
operators<T, U>
+ operators2<T, U>
+ +
+ +

Arithmetic Operators Demonstration and Test + Program

+ +

The operators_test.cpp + program demonstrates the use of the arithmetic operator templates, and + can also be used to verify correct operation. Check the compiler status report for the + test results with selected platforms.

+ +

Dereference Operators and Iterator Helpers

+ +

The iterator helper templates ease the task of + creating a custom iterator. Similar to arithmetic types, a complete + iterator has many operators that are "redundant" and can be implemented + in terms of the core set of operators.

+ +

The dereference operators were motivated by + the iterator helpers, but are often useful in + non-iterator contexts as well. Many of the redundant iterator operators + are also arithmetic operators, so the iterator helper classes borrow many + of the operators defined above. In fact, only two new operators need to + be defined (the pointer-to-member operator-> and the + subscript operator[])!

+ +

The requirements for the types used to instantiate the dereference + operators are specified in terms of expressions which must be valid and + their return type. The composite operator templates list their component + templates, which the instantiating type must support, and possibly other + requirements.

+ +

Dereference Operators

+ +

All the dereference operator templates in this table accept an + optional template parameter (not shown) to be used for base class chaining.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Dereference Operator Template Classes +
+ + + + + + + + + + + + + + + + + + + + +
+ Key +
T: operand typeP: pointer type
D: difference_typeR: reference type
i: object of type T (an + iterator)n: object of type D (an + index)
+
TemplateSupplied OperationsRequirements
dereferenceable<T, + P>P operator->() const(&*i). Return convertible to + P.
indexable<T, D, + R>R operator[](D n) const*(i + n). Return of type + R.
+ +

Grouped Iterator Operators

+ +

There are five iterator operator class templates, each for a different + category of iterator. The following table shows the operator groups for + any category that a custom iterator could define. These class templates + have an additional optional template parameter B, which is + not shown, to support base class chaining.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Iterator Operator Class Templates +
+ + + + + + + + + + + + + + + + + + + + +
+ Key +
T: operand typeP: pointer type
D: difference_typeR: reference type
V: value_type +
+
TemplateComponent Operator Templates
input_iteratable<T, + P> + +
output_iteratable<T> + +
forward_iteratable<T, + P> + +
bidirectional_iteratable<T, + P> + +
random_access_iteratable<T, P, D, + R> + +
+ +

Iterator Helpers

+ +

There are also five iterator helper class templates, each + corresponding to a different iterator category. These classes cannot be + used for base class chaining. The following + summaries show that these class templates supply both the iterator + operators from the iterator operator class + templates and the iterator typedef's required by the C++ standard + (iterator_category, value_type, + etc.).

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Iterator Helper Class Templates +
+ + + + + + + + + + + + + + + + + + + + +
+ Key +
T: operand typeP: pointer type
D: difference_typeR: reference type
V: value_typex1, x2: objects of type T
+
TemplateOperations & Requirements
input_iterator_helper<T, + V, D, P, R> + Supports the operations and has the requirements of + + +
output_iterator_helper<T> + Supports the operations and has the requirements of + + + See also [1], [2]. +
forward_iterator_helper<T, V, D, P, + R> + Supports the operations and has the requirements of + + +
bidirectional_iterator_helper<T, + V, D, P, R> + Supports the operations and has the requirements of + + +
random_access_iterator_helper<T, + V, D, P, R> + Supports the operations and has the requirements of + + + To satisfy RandomAccessIterator, + x1 - x2 with return convertible to D is + also required. +
+ +

Iterator Helper Notes

+ +

[1] Unlike other iterator helpers templates, + output_iterator_helper takes only one template parameter - + the type of its target class. Although to some it might seem like an + unnecessary restriction, the standard requires + difference_type and value_type of any output + iterator to be void (24.3.1 [lib.iterator.traits]), and + output_iterator_helper template respects this requirement. + Also, output iterators in the standard have void pointer and + reference types, so the output_iterator_helper + does the same.

+ +

[2] As self-proxying is the easiest and most common + way to implement output iterators (see, for example, insert [24.4.2] and + stream iterators [24.5] in the standard library), + output_iterator_helper supports the idiom by defining + operator* and operator++ member functions which + just return a non-const reference to the iterator itself. Support for + self-proxying allows us, in many cases, to reduce the task of writing an + output iterator to writing just two member functions - an appropriate + constructor and a copy-assignment operator. For example, here is a + possible implementation of boost::function_output_iterator + adaptor:

 template<class UnaryFunction>
 struct function_output_iterator
@@ -1252,20 +1969,27 @@ struct function_output_iterator
 };
 
-

Note that support for self-proxying does not prevent you from using output_iterator_helper to ease any other, different kind of output iterator's implementation. If output_iterator_helper's target type provides its own definition of operator* or/and operator++, then these operators will get used and the ones supplied by output_iterator_helper will never be instantiated.

+

Note that support for self-proxying does not prevent you from using + output_iterator_helper to ease any other, different kind of + output iterator's implementation. If + output_iterator_helper's target type provides its own + definition of operator* or/and operator++, then + these operators will get used and the ones supplied by + output_iterator_helper will never be instantiated.

-

Iterator Demonstration and Test Program

+

Iterator Demonstration and Test Program

-

The iterators_test.cpp -program demonstrates the use of the iterator templates, and can also be -used to verify correct operation. The following is the custom iterator -defined in the test program. It demonstrates a correct (though trivial) -implementation of the core operations that must be defined in order for -the iterator helpers to "fill in" the rest of the iterator -operations.

+

The iterators_test.cpp + program demonstrates the use of the iterator templates, and can also be + used to verify correct operation. The following is the custom iterator + defined in the test program. It demonstrates a correct (though trivial) + implementation of the core operations that must be defined in order for + the iterator helpers to "fill in" the rest of the iterator + operations.

-
-
template <class T, class R, class P>
+    
+
+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>
@@ -1286,102 +2010,113 @@ public:
   bool operator==(const self& x) const;
   bool operator<(const self& x) const;
   friend Distance operator-(const self& x, const self& y);
-};
-
+}; +
+
-

Check the compiler status report for -the test results with selected platforms.

+

Check the compiler status + report for the test results with selected platforms.

+
-
+

Contributors

-

Contributors

+
+
Dave Abrahams
-
-
Dave Abrahams -
Started the library and contributed the arithmetic operators in - boost/operators.hpp. +
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. +
Jeremy Siek
-
Aleksey Gurtovoy -
Contributed the code to support base class - chaining while remaining backward-compatible with old - versions of the library. +
Contributed the dereference operators and iterator + helpers in boost/operators.hpp. Also + contributed iterators_test.cpp.
-
Beman Dawes -
Contributed operators_test.cpp. +
Aleksey + Gurtovoy
-
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. +
Contributed the code to support base class + chaining while remaining backward-compatible with old versions of + the library.
-
Helmut Zeisel -
Contributed the 'left' operators and added some - grouped operator classes. -
+
Beman Dawes
-

Note for Users of Older Versions

+
Contributed operators_test.cpp.
-

The changes in the library interface and -recommended usage were motivated by some practical issues described -below. The new version of the library is still backward-compatible with -the former one (so you're not forced change any existing code), -but the old usage is deprecated. Though it was arguably simpler and -more intuitive than using base class chaining, -it has been discovered that the old practice of deriving from multiple -operator templates can cause the resulting classes to be much larger -than they should be. Most modern C++ compilers significantly bloat the -size of classes derived from multiple empty base classes, even though -the base classes themselves have no state. For instance, the size of -point<int> from the example -above was 12-24 bytes on various compilers for the Win32 platform, -instead of the expected 8 bytes.

+
Daryle Walker
-

Strictly speaking, it was not the library's fault--the language -rules allow the compiler to apply the empty base class optimization in -that situation. In principle an arbitrary number of empty base classes -can be allocated at the same offset, provided that none of them have a -common ancestor (see section 10.5 [class.derived] paragraph 5 of the -standard). But the language definition also doesn't require -implementations to do the optimization, and few if any of today's -compilers implement it when multiple inheritance is involved. What's -worse, it is very unlikely that implementors will adopt it as a future -enhancement to existing compilers, because it would break binary -compatibility between code generated by two different versions of the -same compiler. As Matt Austern said, "One of the few times when you -have the freedom to do this sort of thing is when you're targeting a new -architecture...". On the other hand, many common compilers will use -the empty base optimization for single inheritance hierarchies.

+
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.
-

Given the importance of the issue for the users of the library (which -aims to be useful for writing light-weight classes like -MyInt or point<>), and the forces -described above, we decided to change the library interface so that the -object size bloat could be eliminated even on compilers that support -only the simplest form of the empty base class optimization. The -current library interface is the result of those changes. Though the -new usage is a bit more complicated than the old one, we think it's -worth it to make the library more useful in real world. Alexy Gurtovoy -contributed the code which supports the new usage idiom while allowing -the library remain backward-compatible.

+
Helmut Zeisel
-
+
Contributed the 'left' operators and added some grouped operator + classes.
-

Revised: 30 Oct 2001

+
Daniel Frey
-

Copyright © David Abrahams and Beman Dawes 1999-2001. -Permission to copy, use, modify, sell and distribute this document is -granted provided this copyright notice appears in all copies. This -document is provided "as is" without express or implied -warranty, and with no claim as to its suitability for any purpose.

+
Contributed the NRVO-friendly and symmetric implementation of + arithmetic operators.
+
- +

Note for Users of Older Versions

+ +

The changes in the library interface and + recommended usage were motivated by some practical issues described + below. The new version of the library is still backward-compatible with + the former one (so you're not forced change any existing code), + but the old usage is deprecated. Though it was arguably simpler and more + intuitive than using base class chaining, it has + been discovered that the old practice of deriving from multiple operator + templates can cause the resulting classes to be much larger than they + should be. Most modern C++ compilers significantly bloat the size of + classes derived from multiple empty base classes, even though the base + classes themselves have no state. For instance, the size of + point<int> from the example + above was 12-24 bytes on various compilers for the Win32 platform, + instead of the expected 8 bytes.

+ +

Strictly speaking, it was not the library's fault--the language rules + allow the compiler to apply the empty base class optimization in that + situation. In principle an arbitrary number of empty base classes can be + allocated at the same offset, provided that none of them have a common + ancestor (see section 10.5 [class.derived] paragraph 5 of the standard). + But the language definition also doesn't require implementations + to do the optimization, and few if any of today's compilers implement it + when multiple inheritance is involved. What's worse, it is very unlikely + that implementors will adopt it as a future enhancement to existing + compilers, because it would break binary compatibility between code + generated by two different versions of the same compiler. As Matt Austern + said, "One of the few times when you have the freedom to do this sort of + thing is when you're targeting a new architecture...". On the other hand, + many common compilers will use the empty base optimization for single + inheritance hierarchies.

+ +

Given the importance of the issue for the users of the library (which + aims to be useful for writing light-weight classes like + MyInt or point<>), and the forces + described above, we decided to change the library interface so that the + object size bloat could be eliminated even on compilers that support only + the simplest form of the empty base class optimization. The current + library interface is the result of those changes. Though the new usage is + a bit more complicated than the old one, we think it's worth it to make + the library more useful in real world. Alexy Gurtovoy contributed the + code which supports the new usage idiom while allowing the library remain + backward-compatible.

+
+ +

Revised: 30 Oct 2001

+ +

Copyright © David Abrahams and Beman Dawes 1999-2001. Permission + to copy, use, modify, sell and distribute this document is granted + provided this copyright notice appears in all copies. This document is + provided "as is" without express or implied warranty, and with no claim + as to its suitability for any purpose.

+ +