<html>
<head>
<title>
 N2293 Standard Library Applications for Explicit Conversion Operators
</title>
<style type="text/css">
  p {text-align:justify}
  li {text-align:justify}
  ins {background-color:#FFFF99}
  del {background-color:#FF9999}
</style>
</head>
<body>
<h1>Standard Library Applications for Explicit Conversion Operators</h1>
Document Number: N2293(07-0153)<br/>
2007-06-22<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 originally in <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1592.pdf">n1592</a>.  One of the key motivating examples is to simplify the 'conversion to unspecified bool' idiom.  (Note: Core wording is being updated to allow explicit bool conversions to work where the language requires them, such as evaluating if statements, and as arguments to && and || operators.)
<p/>
This paper proposes to replace all use of unspecified-bool-type with explicit bool conversion operators.  This will simplify the library clauses and aid clarity by removing pseudo-code from normative signatures and simpliying the associated explanatory text.  In particular, note that hole in the type system that 20.5.14.2.6 [func.wrap.func.undef] works around is closed, removing the whole clause.
<p/>
On the other hand, it deliberately leaves the operator bool() conversion function for the vector&lt;bool> and bitset proxy classes as implicit.
<p/>
While this paper has no suggested applications of the feature beyond boolean conversions, the committee might want to explore explicit
pointer conversion operators for the library smart pointers.
<p/>
The paper would also resolve LWG issues 644 and 686 as NAD.
<p/>
(A couple of Minor editorial nits (typos etc) are also fixed without comment.)

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

<ul>
<li>

<p>
Change 19.4.2.1 [sys.errcode.overview]
</p>

<blockquote><pre>
namespace std {
  class error_code {
  public:

    ...

    // observers:
    value_type value() const;
    con<ins>s</ins>t error_category&amp; category() const;
    posix_errno posix() const;
    string message() const;
    wstring wmessage() const;
    <ins>explicit</ins> operator <del>unspecified-</del>bool<del>-type</del><ins>()</ins> const;

    ...
  };
} <em>// namespace std</em>

...

<ins>explicit</ins> operator <del>unspecified-</del>bool<del>-type</del> () const;
</pre></blockquote>
<p>-11- <em>Returns:</em> <del>If</del> value() != value_type()<del>, returns a value that will evaluate <code>true</code> in a boolean context; otherwise,
returs a value that will evaluate <code>false</code>. The return type shall not be convertible to int.</p></del>
<p>-12- <em>Throws:</em> Nothing.</p>
<p><del>-13- [ Note: This conversion can be used in contexts where a bool is expected (e.g., an if condition); however, implicit
conversions (e.g., to int) that can occur with bool are not allowed, eliminating some sources of user error. One
possible implementation choice for this type is pointer to member. - end note ]</del></p>


</pre>
</li>

<li>

<p>
Change 20.5.14.2 [func.wrap.func]:
</p>

<blockquote><pre>

namespace std {
  template&lt;class&gt; class function; // undefined

  template&lt;class R, class... ArgTypes&gt;
  class function&lt;R(ArgTypes...)&gt;
    : public unary_function&lt;T1, R&gt;	// iff sizeof...(ArgTypes) == 1 and ArgTypes contains T1
    : public binary_function&lt;T1, T2, R&gt;	// iff sizeof...(ArgTypes) == 2 and ArgTypes contains T1 and T2
  {
  public:
    ...

    // 20.5.14.2.3, <em>function capacity:</em>
    <ins>explicit</ins> operator <del>unspecified-</del>bool<del>-type</del> () const;

    ...

    <del>private:
    // 20.5.14.2.6, <em>undefined operators:</em>
    template&lt;class R2, class... ArgTypes2&gt; bool operator==(const function&lt;R2(ArgTypes2...)&gt;&amp;);
    template&lt;class R2, class... ArgTypes2&gt; bool operator!=(const function&lt;R2(ArgTypes2...)&gt;&amp;);</del>
  };
} <em>// namespace std</em>
</pre></blockquote>


<p>
and 20.5.14.2.3 [func.wrap.func.cap]:
</p>

<blockquote><pre>
<ins>explicit</ins> operator <del>unspecified-</del>bool<del>-type</del> () const
</pre></blockquote>
<p>
-1- <em>Returns:</em> if *this has a target<del>,</del> returns <del>a value that will evaluate</del> <code>true</code><del> in a boolean context</del>; otherwise<del>,</del> returns <del>a value that will evaluate </del><code>false</code><del> in a boolean context</del>.<del> The value type returned shall not be convertible to int.</del></p>
<p>
-2- <em>Throws:</em> nothing.<del></p>
<p>-3- [ Note: This conversion can be used in contexts where a bool is expected (e.g., an if condition); however, implicit conversions (e.g., to int) that can occur with bool are not allowed, eliminating some sources of user error. One possible implementation choice for this type is pointer-to-member. - end note ]
</del>
</p>

<p>
and remove 20.5.14.2.6 [func.wrap.func.undef]:
</p>
<del>
20.5.14.2.6 undefined operators [func.wrap.func.undef]
<blockquote><pre>
template&lt;class R2, class... ArgTypes2&gt; bool operator==(const function&lt;R2(ArgTypes2...)&gt;&amp;);
template&lt;class R2, class... ArgTypes2&gt; bool operator!=(const function&lt;R2(ArgTypes2...)&gt;&amp;);
</pre></blockquote>
<p>-1- These member functions shall be left undefined.</p>
<p>-2- [ Note: the boolean-like conversion opens a loophole whereby two function instances can be compared via or !=. These undefined void operators close the loophole and ensure a compile-time error. - end note ]</p>
</del>
</li>

<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 {

...

// observers
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> {

...

// observers
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> {

...

// observers
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 {

  ...

   // 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>

<p>
Change 27.4.4 [ios]
</p>

<blockquote><pre>
namespace std {
  template &lt;class charT, class traits = char_traits&lt;charT> >
  class basic_ios : public ios_base {
  public:

    ...

    <ins>explicit</ins> operator <del>unspecified-</del>bool<del>-type</del> () const;

  };
}
</pre></blockquote>

<p>and 27.4.4.3 [iostate.flags]:</p>
<blockquote><pre>
<ins>explicit</ins> operator <del>unspecified-</del>bool<del>-type</del> () const;</pre></blockquote>

<p>-1- <em>Returns:</em> <del>If</del> <code><ins>!</ins>fail()</code><del> then a value that will evaluate <code>false</code> in a boolean context; otherwise a value that will evaluate <code>true</code> in a boolean context. The value type returned shall not be convertible to int.</del></p>
<p><del>[ Note: This conversion can be used in contexts where a bool is expected (e.g., an if condition); however, implicit conversions (e.g., to int) that can occur with bool are not allowed, eliminating some sources of user error. One
possible implementation choice for this type is pointer-to-member. - end note ]</del></p>
</li>


<li>

<p>
Change 27.6.1.1.3 [istream::sentry]
</p>

<blockquote><pre>
namespace std {
  template &lt;class charT,class traits = char_traits&lt;charT> >
  class basic_istream&lt;charT,traits>::sentry {
    typedef traits traits_type;
    // bool ok_; exposition only
  public:
    explicit sentry(basic_istream&lt;charT,traits>&amp; is , bool noskipws = false);
    ~sentry();
    <ins>explicit</ins> operator bool() const { return ok_; }
  private:
    sentry(const sentry&amp;); // not defined
    sentry&amp; operator=(const sentry&amp;); // not defined
  };
}
</pre></blockquote>

</li>

<li>

<p>
Change 27.6.2.4 [ostream::sentry]
</p>

<blockquote><pre>
namespace std {
  template &lt;class charT,class traits = char_traits&lt;charT> >
  class basic_ostream&lt;charT,traits>::sentry {
    <em>// bool ok_; exposition only</em>
  public:
    explicit sentry(basic_ostream&lt;charT,traits>&amp; <em>os</em>);
    ~sentry();
    <ins>explicit</ins> operator bool() const { return <em>ok_</em>; }
  private:
    sentry(const sentry&amp;); // not defined
    sentry&amp; operator=(const sentry&amp;); // not defined
  };
}
</pre></blockquote>

</li>

</body>
</html>
