Boost logo

Boost :

From: Søren Lassen (s.lassen_at_[hidden])
Date: 2005-04-25 11:14:55


I have found a couple of "undocumented features" in operators.hpp:

1) The return values from a lot of the binary operators should be declared
const, so that it is not possible to assign to the temporary object that
results from the operation. An example:

        if(!(a/b=c/d))...

This statement is obviously a typo. The assignment operator= should have
been a comparison operator==. With the current definition of operator/ in
operators.hpp, the compiler will not recognize this as an error. Instead,
the following will happen: first, the values of a/b and b/c are calculated
and placed in temporary objects. Then, the result of a/b is overwritten by
the result of c/d. Finally, operator! converts that to a boolean and the
if statement acts on it (in other words, the statement is probably
interpreted as "if(!c)..."). If, on the other hand, the return value from
operator/ is declared constant, the compiler will catch the error, and
probably say something like "lvalue required". Much better.

2) I think the "Named Return Value Optimization" code is a
misunderstanding. The way I read the excerpts from the C++ standard quoted
in the documentation (see
http://www.boost.org/libs/utility/operators.htm#symmetry) is as follows:

The standard places some limits on when NAMED objects may be optimized
away. From this follows implicitly that UNNAMED objects may always be
optimized away. Or, to quote from Scott Meyers' "More Effective C++", page
109-110: "However, the fact remains that unnamed objects have historically
been easier to eliminate than named objects, so when faced with a choice
between a named object and a temporary object, you may be better off using
the temporary. It should never cost you more than its named collegue, and,
especially with older compilers, it may cost you less".

In other words: some compilers may not have Named Return Value
Optimization, but most of them have (Unnamed) Return Value Optimization,
which means that temporary, unnamed objects are optimized away where
possible.

So, I think, a better way of writing e.g. operator+ is the good
old-fashioned:
template <class T>
    inline const T operator+(const T& lhs,const T& rhs)
       {return T(lhs) += rhs;};

3) When using compilers that do not support operators in namespaces
(#ifdef BOOST_NO_OPERATORS_IN_NAMESPACE), the operator templates are first
placed in the global namespace, and then copied to the boost namespace.
The consequence of this is that it is not possible to access the templates
with a "using namespace boost;" declaration - trying to do so creates an
ambiguity between the stuff in boost and the stuff in the global
namespace. Also, of course, the global namespace is "polluted" with quite
a lot of extra names. The solution to this problem is to declare all the
templates inside a "pseudo-namespace" struct in the global namespace -
this also makes it easier to import the templates into boost, as even the
Borland compiler now recognizes a "using" declaration.

I have uploaded a new version of "operators.hpp" with fixes for
above-mentioned problems to the sandbox vault. It has been tested with
"rational.hpp" on the Borland 5.5 compiler and the Microsoft version
13.10.3077 compiler (the one that comes with the free Visual Toolkit 2003,
and also (I think) with Visual C++ 7.1). I hope that some of you have time
to test my new version with other programs and compilers.

---
Søren

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk