<html>
<head>
<title>
 N2435 Explicit bool for Smart Pointers
</title>
<base href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/" />
<style type="text/css">
  p {text-align:justify}
  li {text-align:justify}
  ins {background-color:#FFFF99}
  del {background-color:#FF9999}
</style>
</head>
<body>
<h1>Explicit bool for Smart Pointers</h1>
Document Number: N2435(07-0305)<br/>
2007-10-03<br/>
Alisdair Meredith &lt;public@alisdairm.net><br/>
<h2>Background and Rationale</h2>
One feature of the next version of the C++ Language will be Explicit Conversion operators, as descibed in <a href="../2007/n2380.pdf">n2380</a>.  One of the key motivating examples is to avoid usage of the 'conversion to unspecified bool' idiom. This is an awkward technique to teach, and should not be required learning for such an important idiom as smart pointers. It also falls under the stated goal of 'removing embarrasments' from C++0x.
<p/>
The first version of this paper (<a href="../2007/n2293">N2293</a>) raised
concerns when applied to smart pointer types, so that part has been extracted
into this separate proposal to be handled independantly.
<h2>Issues unique to smart pointers</h2>
<p/>
There are two use cases for the unspecified-bool-idiom that an explicit bool conversion operator cannot solve - comparison with the null pointer literal and use as a function parameter/return value.
<blockquote><pre>
template&lt; class T >
struct ptr {
  ...
  explicit operator bool() { return p; }
  T * p;
};

ptr&lt; int > p;

// This code compiles with unspecified-bool-idiom
// Will not compile for an explicit bool conversion operator
if( p == 0 ) {}
if( p != 0 ) {}
if( 0 == p ) {}
if( 0 != p ) {}

// Function parameter passing and return values use copy initialization
// This code compiles with unspecified-bool-idiom
// Will not compile for an explicit bool conversion operator
void test( bool );
test( p );
bool test( ptr p ) { return p; }
</pre></blockquote>

<p/>
<h2>Resolution</h2>
This paper proposes to replace all use of unspecified-bool-type with explicit bool conversion operators.  In order to support comparison with the null
pointer literal each smart pointer acquires a converting constructor for
the new <code>std::nullptr_t</code> type. This constructor delegates to the
default constructor, to initialize as an empty pointer.
<p/>
In addition to solving the comparison with null pointer literal problem, the
converting constructor also permits assignment from a null pointer literal,
which is effectively the same as a <code>reset</code>.

<blockquote><pre>
template&lt; class T >
struct ptr {
  ...
  ptr( nullptr_t ) : ptr() {}
  explicit operator bool() { return p; }
  T * p;
};

ptr&lt; int > p;

// This code now compiles via nullptr_t conversting constructor
if( p == 0 ) {}
if( p != 0 ) {}
if( 0 == p ) {}
if( 0 != p ) {}

// This code also compiles via nullptr_t conversting constructor
p = 0;

</pre></blockquote>

<p/>
The paper would also resolve LWG issue 686 as NAD.
<p/>

<h2>Proposed Changes to Working Draught (n2369)</h2>

<ul>
<li>

<p>
Change 20.6.5.2 [unique.ptr.single]:
</p>

<blockquote><pre>
template &lt;class T, class D = default_delete&lt;T&gt;&gt; class unique_ptr {

  ...

  <em>// constructors</em>
  unique_ptr();
  explicit unique_ptr(T* p);
  unique_ptr(T* p, <em>implementation defined (see description below)</em> d);
  unique_ptr(T* p, <em>implementation defined (see description below)</em> d);
  unique_ptr(unique_ptr&& u);
  <ins>unique_ptr(nullptr_t) : unique_ptr() {}</ins>
  template &lt;class U, class E> unique_ptr(unique_ptr&lt;U, E>&& u);

  ...

  <em>// observers</em>
  T& operator*() const;
  T* operator->() const;
  T* get() const;
  deleter_type& get_deleter();
  const deleter_type& get_deleter() const;
  <ins>explicit</ins> operator <del>unspecified-</del>bool<del>-type</del> () const;

  ...

};
</pre></blockquote>

<p> and 20.6.5.2.4 [unique.ptr.single.observers]</p>
<blockquote><pre>
<ins>explicit</ins> operator <del>unspecified-</del>bool<del>-type</del> () const;
</pre></blockquote>
<p>-11- <em>Returns:</em> <del>An unspecified value that, when used in boolean contexts, is equivalent to</del> <code>get() != 0</code>.</p>
<p>-12- <em>Throws:</em> nothing.</p>
<p><del>-13- [ Note: The unspecified-bool-type is often implemented as a pointer to a private data member, avoiding many of the implicit conversion pitfalls. - end note ]</del></p>


<p>
and 20.6.5.3 [unique.ptr.runtime]:
</p>

<blockquote><pre>
template &lt;class T, class D> class unique_ptr&lt;T[], D> {

  ...

  <em>// constructors</em>
  unique_ptr();
  explicit unique_ptr(T* p);
  unique_ptr(T* p, <em>implementation defined</em> d);
  unique_ptr(T* p, <em>implementation defined</em> d);
  unique_ptr(unique_ptr&& u);
  <ins>unique_ptr(nullptr_t) : unique_ptr() {}</ins>

  ...

  <em>// observers</em>
  T& operator[]() const;
  T* get() const;
  deleter_type& get_deleter();
  const deleter_type& get_deleter() const;
  <ins>explicit</ins> operator <del>unspecified-</del>bool<del>-type</del> () const;

  ...

};
</pre></blockquote>

<p>
and 20.6.5.4 [unique.ptr.compiletime]:
</p>

<blockquote><pre>
template &lt;class T, class D, size_t N> class unique_ptr&lt;T[N], D> {

  ...

  <em>// constructors</em>
  unique_ptr();
  explicit unique_ptr(T* p);
  unique_ptr(T* p, <em>implementation defined</em> d);
  unique_ptr(T* p, <em>implementation defined</em> d);
  unique_ptr(unique_ptr&& u);
  <ins>unique_ptr(nullptr_t) : unique_ptr() {}</ins>

  ...

  <em>// observers</em>
  T& operator[]() const;
  T* get() const;
  deleter_type& get_deleter();
  const deleter_type& get_deleter() const;
  <ins>explicit</ins> operator <del>unspecified-</del>bool<del>-type</del> () const;

  ...

};
</pre></blockquote>

</li>

<li>

<p>
Change 20.6.6.2 [util.smartptr.shared]:
</p>

<blockquote><pre>
namespace std {
  template<class T> class shared_ptr {

  ...
  
  <em>// 20.6.6.2.1, constructors:</em>
  shared_ptr();
  template&lt;class Y> explicit shared_ptr(Y* p);
  template&lt;class Y, class D> shared_ptr(Y* p, D d);
  template&lt;class Y, class D, class A> shared_ptr(Y* p, D d, A a);
  template&lt;class Y> shared_ptr(shared_ptr&lt;Y> const& r, T *p);
  shared_ptr(shared_ptr const& r);
  template&lt;class Y> shared_ptr(shared_ptr&lt;Y> const& r);
  shared_ptr(shared_ptr&& r);
  template&lt;class Y> shared_ptr(shared_ptr&lt;Y>&& r);
  template&lt;class Y> explicit shared_ptr(weak_ptr&lt;Y> const& r);
  template&lt;class Y> explicit shared_ptr(auto_ptr&lt;Y>& r);
  <ins>shared_ptr(nullptr_t) : shared_ptr() {}</ins>

   // 20.6.6.2.5, observers:
  T* get() const;
  T& operator*() const;
  T* operator->() const;
  long use_count() const;
  bool unique() const;
  <ins>explicit</ins> operator <del>unspecified-</del>bool<del>-type</del> () const; };
} <em>// namespace std</em>
</pre></blockquote>

<p>
and 20.6.6.2.5 [util.smartptr.shared.obs]
</p>

<blockquote><pre>
 <ins>explicit</ins> operator <del>unspecified-</del>bool<del>-type</del> () const;</pre></blockquote>
<p>-16- <em>Returns:</em> <del>an unspecified value that, when used in boolean contexts, is equivalent to </del><code>get() != 0</code>.</p>
<p>-17- <em>Throws:</em> nothing.</p>
<p><del>-18- [ <em>Note:</em> This conversion operator allows shared_ptr objects to be used in boolean contexts. [ Example: if (p
&& p->valid()) - end example ] One possible choice for the return type is a pointer to member function, which avoids many of the implicit conversion pitfalls of a bool or void* return type. - <em>end note</em> ]</del></p>


</li>

</body>
</html>
