$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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 
example:
template <class InputIterator, class Distance>
void
advance(InputIterator& i, Distance n);
That is what we meant.  But to the compiler we wrote:
template <class T, class U>
void
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>
void
f(S_ptr<X> px)
{
     static_assert(!is_array<X>::value, "X must not be an array type");
     ...
}
Reference:
     http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1424.htm
     http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1381.htm
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>
void
f(S_ptr<X> px)
{
     px.reset();
}
If the attempted syntax is not common, then it will likely not work:
template<class X>
void
f(S_ptr<X> px)
{
     *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 
element.
vector<clone_ptr<T> >   :  copy uses t->clone() to "deep copy" each 
element.
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 
clone_ptr<T[N]>).
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?
-Howard