Boost logo

Boost :

From: Dave Abrahams (abrahams_at_[hidden])
Date: 1999-12-20 22:19:12


Paul wrote:

> The ideal user interface for the rational class would be
>
> using boost::rational;

I'll quibble with the above, but it doesn't really change anything. There's
no reason to assume this is more ideal than using full qualification.

> rational<int> r = ...;
> r = abs(r);
>
> This usage is sanctioned by Koenig lookup (std: 3.4.2).

// DEMARCATE NON-STANDARD SUPPORT

> For compilers which don't implement Koenig lookup, it is necessary to add a
> "using boost::abs", to make the abs(rational) declaration visible. There is no
> workaround here - this need is precisely what Koenig lookup was developed to
> remove.

Better yet, just put the abs specialization for rational<> into the global
namespace.

> On the implementation side, abs(rational<I>) needs to be implemented in terms
of
> (unqualified) abs(I), so that the unqualified lookup rules can come into play
to
> find an appropriate abs() for I. To cater for I being int or long, a suitably
> placed "using std::abs" is needed.

Sounds right to me

> Friend templates
> ----------------
>
> The correct syntax for a friend template declaration is
>
> friend rational<IntType> abs<> (const rational<IntType>);
>
> (std 14.5.3). I say this with some hesitation, as MSVC generated compiler
errors
> with some variations on this, and gcc wasn't too robust - and my reading of
the
> standard is slightly confused here.
>
> In this instance, rational<> exposes numerator() and denominator() member
> functions, and so abs() doesn't need to be a friend, in practice.
>
> I would categorise friend templates as not yet well enough supported to use.

Your sample is too small, but that doesn't really matter. Why bother with
friend templates when abs doesn't need to be a friend at all?

Speaking of friends, you could use the Barton & Nackmann trick if partial
ordering doesn't work in MSVC (does it?):

template <class X>
struct rational_abs
{
    friend abs(const X& x)
    { using std::abs; return X(abs(x.numerator(), x.denominator()); }
};

template <class T>
class rational : rational_abs<rational<T> >, ...

> MSVC bugs
> ---------
>
> We know MSVC doesn't implement Koenig lookup, and doesn't like friend
templates.
> OK, call these bugs or "not yet supported new language features". Regardless,
we
> know how to deal with them.
>
> The big problems are
>
> - MSVC doesn't put the contents of <cstdlib> in std::
> - This is compounded by broken name lookup rules
>
> The lack of std::abs should in theory just mean that we don't need a using
> std::abs() in the implementation of abs(rational<I>). Unfortunately, it looks
> like MSVC compounds this by failing to follow std 3.4.1.6, by not counting
::abs
> as a candidate for overloading along with boost::abs. Or maybe it isn't doing
> the overloading rules correctly - wasn't there an older overloading rule which
> preferred "closer" declarations over "further away" ones? Regardless, MSVC
isn't
> doing what the standard says.
>
> Actually, on a close reading of 3.4.1.6, "A name used in the definition of a
> function..." I note that no explicit mention is made of the global scope
> (although you could argue that the global scope encloses all namespace scopes
-
> but I couldn't find words to that effect - and the example does imply that it
is
> intended to be included). I'm sure that either I missed something, or this is
> worth a defect report - it is clearly intended.
>
> Anyway, as a consequence, it is necessary to import ::abs() [what should have
> been std::abs()] into namespace boost under MSVC, in order to let MSVC resolve
> abs(int) correctly.

Try the B&N trick described above. That should solve a lot of problems by
not requiring so much template smarts from the compiler. This would simply
generate a single abs() overload for each version of rational. Hmm, though
to get abs() into the global namespace you might need to put rational_abs
there, too. Maybe you need to call it boost_rational_abs__() for MSVC's
purposes.

> Template Instantiation
> ----------------------
>
> I am still not 100% sure what would be needed to ensure that we could
> instantiate rational<> with a class (in namespace pfm) pfm::bigint, where
there
> was a defined pfm::abs(pfm::bigint). I am pretty sure that as long as we avoid
> friend templates, we're OK on compilers which implement Koenig lookup. But
what
> we'd need to work around a lack of Koenig lookup in this case, I really don't
> know. Probably import pfm::abs into the boost namespace, with an abomination
> like
>
> namespace boost {
> using pfm::abs;
> // possibly even using pfm::bigint; !!
> }
>
> in *client* code.

On broken compilers, the bigint implementer had better put the abs() in the
global namespace as I have been proposing, or I think we are sunk.
 


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