fine tunings

This commit is contained in:
Frank B. Brokken 2017-02-10 21:14:47 +01:00
parent e13a914aef
commit ac4918a7a9
3 changed files with 36 additions and 28 deletions

View file

@ -13,10 +13,9 @@ example).
Since template functions are not instantiated before they are actually used we
can call non-existing functions from template functions that are never
instantiated. If such a template function is If such a template function is
never instantiated, nothing happens; if it is (accidentally) instantiated,
then the compiler generates an error message, complaining about the missing
function.
instantiated. If such a template function is never instantiated, nothing
happens; if it is (accidentally) instantiated, then the compiler generates an
error message, complaining about the missing function.
This allows us to implement all binary operators, movable and non-movable, as
templates. In the following subsections we develop the class template

View file

@ -60,18 +60,16 @@ The implementation of this free tt(operator+=) function looks like this:
}
)
------------------------------------------------------
The flexibility of this design is augmented
further after realizing that the right-hand side operand doesn't have to be a
tt(Derived) class object. Consider tt(operator<<): oftentimes shifts are
bit-shifts, using a tt(size_t) to specify the number of bits to
shift. In fact, the type of the right-hand side operand can completely be
generalized by defining a second template type parameter, which is used to
specify the right-hand side's operand type. It's up to the tt(Derived) class
to specify the argument type of its tt(operator+=) (or any other binary
compound operator), whereafter the compiler will deduct the types of the
right-hand side operands for the remaining binary operators. Here is the
final implementation of the free
The flexibility of this design can be further augmented once we realize that
the right-hand side operand doesn't have to be a tt(Derived) class
object. Consider tt(operator<<): oftentimes shifts are bit-shifts, using a
tt(size_t) to specify the number of bits to shift. In fact, the type of the
right-hand side operand can completely be generalized by defining a second
template type parameter, which is used to specify the right-hand side's
operand type. It's up to the tt(Derived) class to specify the argument type of
its tt(operator+=) (or any other binary compound operator), whereafter the
compiler will deduct the types of the right-hand side operands for the
remaining binary operators. Here is the final implementation of the free
tt(operator+=) function:
verb(
template <class Derived, typename Rhs>

View file

@ -1,16 +1,16 @@
Classes also frequently define overloaded insertion and extraction
operators. Since there are no `compound insertion operators' the approach
covered above cannot be used when overloading these operators. Instead using
operators. Since there are no `compound insertion operators' the design shown
so far cannot be used when overloading these operators. Instead using
standardized member function signatures is advocated: tt(void
insert(std::ostream &out) const) to insert an object into an tt(ostream) and
tt(void extract(std::istream &in) const) to extract an object from an
tt(istream). As these functions are only used by, respectively, the
insertion and extraction operators, they can be declared in the tt(Derived)
class's private interface. Instead of declaring the insertion and extraction
operators friends of the class tt(Derived) a simpler tt(friend
Binops<Derived>) is specified. This allows tt(Binops<Derived>) to define
private, inline tt(iWrap) and tt(eWrap) members, merely calling, respectively,
tt(Derived's insert) and tt(extract) members:
tt(istream). As these functions are only used by, respectively, the insertion
and extraction operators, they can be declared in the tt(Derived) class's
private interface. Instead of declaring the insertion and extraction operators
friends of the class tt(Derived) a single tt(friend Binops<Derived>) is
specified. This allows tt(Binops<Derived>) to define private, inline tt(iWrap)
and tt(eWrap) members, merely calling, respectively, tt(Derived's insert) and
tt(extract) members:
verb(
template <typename Derived>
inline void Base<Derived>::iWrap(std::ostream &out) const
@ -18,9 +18,11 @@ tt(Derived's insert) and tt(extract) members:
static_cast<Derived const &>(*this).insert(out);
}
)
tt(Base<Derived>) also declares the insertion and extraction operators
as its friends, allowing these operators to call, respectively, tt(iWrap) and
tt(eWrap). Here is the implementation of the overloaded insertion operator:
tt(Base<Derived>) then declares the insertion and extraction operators as
its friends, allowing these operators to call, respectively, tt(iWrap) and
tt(eWrap). Note that the software engineer designing the class tt(Derived)
only has to provide a tt(friend Base<Derived>) declaration. Here is the
implementation of the overloaded insertion operator:
verb(
template <typename Derived>
std::ostream &operator<<(std::ostream &out, Base<Derived> const &obj)
@ -29,3 +31,12 @@ tt(eWrap). Here is the implementation of the overloaded insertion operator:
return out;
}
)
This completes the coverage of the essentials of a class template tt(Binops)
potentially offering binary operators and insertion/extraction operators for
any class derived from tt(Binops). Finally, as noted at the beginning of this
section, a complete implementation of a class offering addition and insertion
operators is provided in the file
tt(annotations/yo/concrete/examples/binopclasses.cc) in the annotations()'
source archive.