Boost logo

Boost :

From: Dave Abrahams (abrahams_at_[hidden])
Date: 2000-01-23 19:01:01

Valentin wrote:

> Dave Abrahams wrote:
>> In generic programs, there are two ways to allow users to customize
>> behaviors of called functions for their own types:
>> 1. We can use overloading and rely on Koenig lookup to help select specific
>> implementations.
>> 2. We can supply a function template and rely on the user to specialize it
>> for her own types.
> 3. For namespaces different from std, use overloading in only one
> namespace
> for things that can be overloaded (functions), and do not rely on
> Koenig lookup but, on the contrary, use qualified names; user
> code adds overloads directly in the library namespace
> use specialisations for things which can't (classes)

Okay, but let me get this straight (I think my sanity is back):

For template functions which are defined in std (e.g. swap) we are allowed
to FULLY specialize on a user-defined type, but we are not allowed to
"partially specialize" (write an overload which should be selected by
partial ordering) on a user-defined type.

For example:

namespace NS {
class X {...};
template <class T> class Y {...};

namespace std {
// 1. legal full specialization
template <> void swap(NS::X&, NS::X&);
// 2. illegal "partial" specialization (actually an overload)
template <class T> void swap(NS::Y<T>&, NS::Y<T>&) {};

But inside of boost, we are free to allow overloads like #2 above.
Furthermore, we have no idea why they are prohibited in std.

> In any cases, when adding something to a namespace, follow the
> requirements of the name of the thing being added.

For example, a full specialization of std::swap must swap the values of its

> This works w/o reserving function names in every namespace,
> and allows complete parametrisation by library users.


>> (e.g., how would you write an abs that works for unsigned?)
> Seems to me that
> namespace boost {
> unsigned abs (unsigned x) { return x; }
> unsigned long abs (unsigned long x) { return x; }
> }
> does the job.

My original quote was:

<<I think it's an open question whether option 2 can be applied effectively
in cases where there isn't a generalizable implementation for the function
(e.g., how would you write an abs that works for unsigned?)>>

Option 2 involved starting with a function template, and allowing the user
to specialize it for their own types.

What I meant was that it isn't clear that option 2 is appropriate for all
combinations of types and operations. For a better example, suppose you
wanted to supply a negation function - it wouldn't apply to unsigned.

Now that my sanity has returned I understand that we would probably just use
overloading inside of boost to handle that case.

So my current conclusion is that Koenig lookup is fine for code which
doesn't depend on template parameters (as a way to avoid writing too many
namespace qualifications). Code in templates, however, should be written to
avoid finding functions in the namespaces of template parameters through
Koenig lookup, since that practice effectively "reserves" the name in the
namespace of that template parameter, and can result in unexpected
ambiguities**. The exception is code in std, which (because of prohibitions
against overloading in std), MUST rely on Koenig lookup for functions like
abs or swap which it is expecting the user to customize. On the other hand,
implementors of the standard library should probably be cautious and
explicitly qualify most function calls to avoid causing conflicts with names
which the user reasonably believes he can use safely within his own


** having trouble coming up with a good, small example of this right now,
but have seen it recently in my work with the STLport, where there is a
separate namespace containing debug versions of many functions and debug
wrappers for container iterators. If someone can produce a small example of
the problem, I'd be indebted.

Boost list run by bdawes at, gregod at, cpdaniel at, john at