Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2004-01-27 19:39:47

On Jan 27, 2004, at 11:06 AM, Peter Dimov wrote:

>> Need to be? No. But I still like it. <shrug> I was convinced
>> because that's how a newbie expected it to work.
> I'm starting to not like it. :-) The problem is:
> template<class X> void f(S_ptr<X> px);
> where f doesn't support arrays. A reasonably common occurence.
> S_array<>
> doesn't match, but S_ptr<T[]> does. The author of f would need to learn
> about enable_if to prevent array pointers from being passed to f. This
> is
> not good, although the exact degree of not-goodness is somewhat
> debatable.

I understand your hesitation. But I'm not yet seeing a concrete case
to support it.

There are two situations to analyze here:

1. Client writes:

    template<class X> void f(S_ptr<X> px);

and intends to catch only pointers to single objects, and does not want
to deal with pointers to arrays.

2. Client writes:

    template<class X> void f(S_ptr<X> px);

and intends to catch pointers to both single objects and array objects.

In case 1, learning about enable_if is not necessarily a bad thing.
Indeed, a significant portion of the standard headers would be much
better behaved today if we (as a community) had better understood the
value of restricted templates, how to implement them, and the dangers
of templates with unrestricted syntax, but restricted semantics. For

template <class InputIterator, class Distance>
advance(InputIterator& i, Distance n);

That is what we meant. But to the compiler we wrote:

template <class T, class U>
advance(T& x, U y);

The difference is really startling. Learning about enable_if is a
feature, not a bug! :-)

Now if the author intends case 1, enable_if is only one route to take.
Another very easy thing to say is:

template<class X>
f(S_ptr<X> px)
     static_assert(!is_array<X>::value, "X must not be an array type");


This boils down to: Is S_ptr<X[]> going to become a familiar enough
idiom that the average C++ programmer is going to be educated enough to
deal with it? That's a real question. Imho we either fully embrace it
or fully abandon it.

In case 2, where the programmer wants to collect smart pointers to
single objects and arrays, then the syntax is clearly a benefit (as
Bronek pointed out earlier in this thread). There isn't a whole lot
that a client could do with both S_ptr<X> and S_ptr<X[]>, but that cuts
both ways: If the attempted syntax is common, it will likely work:

template<class X>
f(S_ptr<X> px)

If the attempted syntax is not common, then it will likely not work:

template<class X>
f(S_ptr<X> px)

Are there use cases where a programmer could naively assume 1, but end
up with 2? Are there use cases where you really need 2? Looking for
good use cases....

I've been exploring copy_ptr and clone_ptr lately. There is a
connection that may be relevant. Consider vector<S_ptr<T> >. When you
copy that container, what should be the semantics?

vector<shared_ptr<T> > : copy shares ownership with source

vector<move_ptr<T> > : copy not possible, but can move (transfer)
ownership from source to target

vector<copy_ptr<T> > : copy uses new T(*t) to "deep copy" each

vector<clone_ptr<T> > : copy uses t->clone() to "deep copy" each

In the first two cases, if T turns out to be an array type, there isn't
that much to be concerned about. But in the latter two cases if T is
an array type, you really need to know how many elements are in the
array to pull off a correct copy. So...

vector<copy_ptr<int[3]> > : copy_ptr's copy ctor could know how many
elements are in the array and do the right thing (and similarly for

copy_ptr<T[N]> would only be convertible to copy_ptr<T[M]> if N == M.

copy_ptr<T[]> would not be copyable at all because it doesn't know how
many elements to copy.

I'm just kind of rambling in public (which is always a foolish thing to
do). I haven't prototyped any of this yet. Thoughts?


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