Updated value_initialized documentation and test following changeset [51355].

[SVN r51356]
This commit is contained in:
Niels Dekker 2009-02-20 20:35:34 +00:00
parent 5f0cf4f5de
commit 0af1959b30
2 changed files with 47 additions and 23 deletions

View File

@ -253,7 +253,33 @@ its internal data, prior to constructing the object that it contains.
<h2><a name="val_init"><code>template class value_initialized&lt;T&gt;</code></a></h2> <h2><a name="val_init"><code>template class value_initialized&lt;T&gt;</code></a></h2>
<pre>namespace boost {<br><br>template&lt;class T&gt;<br>class value_initialized<br>{<br> public :<br> value_initialized() : x() {}<br> operator T&amp;() const { return x ; }<br> T&amp; data() const { return x ; }<br> void swap( value_initialized&lt;T&gt;&amp; );<br><br> private :<br> <i>unspecified</i> x ;<br>} ;<br><br>template&lt;class T&gt;<br>T const&amp; get ( value_initialized&lt;T&gt; const&amp; x )<br>{<br> return x.data() ;<br>}<br><br>template&lt;class T&gt;<br>T&amp; get ( value_initialized&lt;T&gt;&amp; x )<br>{<br> return x.data() ;<br>}<br><br>} // namespace boost<br></pre> <pre>namespace boost {<br><br>template&lt;class T&gt;<br>class value_initialized<br>{
<br> public :
<br> value_initialized() : x() {}
<br> operator T const &amp;() const { return x ; }
<br> operator T&amp;() { return x ; }
<br> T const &amp;data() const { return x ; }
<br> T&amp; data() { return x ; }
<br> void swap( value_initialized&lt;T&gt;&amp; );
<br>
<br> private :
<br> <i>unspecified</i> x ;
<br>} ;
<br>
<br>template&lt;class T&gt;
<br>T const&amp; get ( value_initialized&lt;T&gt; const&amp; x )
<br>{
<br> return x.data() ;
<br>}
<br>
<br>template&lt;class T&gt;
<br>T&amp; get ( value_initialized&lt;T&gt;&amp; x )
<br>{
<br> return x.data() ;
<br>}
<br>
<br>} // namespace boost
<br></pre>
<p>An object of this template class is a <code>T</code>-wrapper convertible <p>An object of this template class is a <code>T</code>-wrapper convertible
to <code>'T&amp;'</code> whose wrapped object (data member of type <code>T</code>) to <code>'T&amp;'</code> whose wrapped object (data member of type <code>T</code>)
@ -271,7 +297,8 @@ its internal data, prior to constructing the object that it contains.
<code>T&amp;</code>, the member function <code>data()</code>, or the <code>T&amp;</code>, the member function <code>data()</code>, or the
non-member function <code>get()</code>: </p> non-member function <code>get()</code>: </p>
<pre>void watch(int);<br>value_initialized&lt;int&gt; x;<br><br>watch(x) ; // operator T&amp; used.<br>watch(x.data());<br>watch( get(x) ) // function get() used</pre> <pre>void watch(int);<br>value_initialized&lt;int&gt; x;
<br><br>watch(x) ; // operator T&amp; used.<br>watch(x.data());<br>watch( get(x) ) // function get() used</pre>
<p>Both <code>const</code> and non-<code>const</code> objects can be wrapped. <p>Both <code>const</code> and non-<code>const</code> objects can be wrapped.
Mutable objects can be modified directly from within the wrapper but constant Mutable objects can be modified directly from within the wrapper but constant
@ -281,37 +308,34 @@ non-member function <code>get()</code>: </p>
is swappable as well, by calling its <code>swap</code> member function is swappable as well, by calling its <code>swap</code> member function
as well as by calling <code>boost::swap</code>.</p> as well as by calling <code>boost::swap</code>.</p>
<pre>value_initialized&lt;int&gt; x ; <br>static_cast&lt;int&amp;&gt;(x) = 1 ; // OK<br>get(x) = 1 ; // OK<br><br>value_initialized&lt;int const&gt; y ; <br>static_cast&lt;int&amp;&gt;(y) = 1 ; // ERROR: cannot cast to int&amp;<br>static_cast&lt;int const&amp;&gt;(y) = 1 ; // ERROR: cannot modify a const value<br>get(y) = 1 ; // ERROR: cannot modify a const value</pre> <pre>value_initialized&lt;int&gt; x ; <br>static_cast&lt;int&amp;&gt;(x) = 1 ; // OK<br>get(x) = 1 ; // OK
<br><br>value_initialized&lt;int const&gt; y ; <br>static_cast&lt;int&amp;&gt;(y) = 1 ; // ERROR: cannot cast to int&amp;<br>static_cast&lt;int const&amp;&gt;(y) = 1 ; // ERROR: cannot modify a const value<br>get(y) = 1 ; // ERROR: cannot modify a const value</pre>
<h3>Warning:</h3> <h3>Warning:</h3>
<p>Both the conversion operator and the <code>data()</code> member function <p>The <code>value_initialized</code> implementation of Boost version 1.38.0 and older
are <code>const</code> in order to allow access to the wrapped object allowed <i>non-const</i> access to the wrapped object, from a constant wrapper,
from a constant wrapper:</p> both by its conversion operator and its <code>data()</code> member function. For example:</p>
<pre>void foo(int);<br>value_initialized&lt;int&gt; const x ;<br>foo(x);<br></pre> <pre>value_initialized&lt;int&gt; const x_c ;<br>int&amp; xr = x_c ; // OK, conversion to int&amp; available even though x_c is itself const.
<br>xr = 2 ; </pre>
<p>But notice that this conversion operator is to <code>T&amp;</code> although <p>The reason for this obscure behavior was that some compilers
it is itself <code>const</code>. As a consequence, if <code>T</code> is didn't accept the following valid code:</p>
a non-<code>const</code> type, you can modify the wrapped object even from
within a constant wrapper:</p>
<pre>value_initialized&lt;int&gt; const x_c ;<br>int&amp; xr = x_c ; // OK, conversion to int&amp; available even though x_c is itself const.<br>xr = 2 ; </pre>
<p>The reason for this obscure behavior is that some commonly used compilers
just don't accept the following valid code:</p>
<pre>struct X<br>{<br> operator int&amp;() ;<br> operator int const&amp;() const ; <br>};<br>X x ;<br>(x == 1 ) ; // ERROR HERE!</pre> <pre>struct X<br>{<br> operator int&amp;() ;<br> operator int const&amp;() const ; <br>};<br>X x ;<br>(x == 1 ) ; // ERROR HERE!</pre>
<p>These compilers complain about ambiguity between the conversion operators. <p>The current version of <code>value_initialized</code> no longer has this obscure behavior.
This complaint is incorrect, but the only workaround that I know of is As compilers nowadays widely support overloading the conversion operator by having a <code>const</code> and a <code>non-const</code> version, we have decided to fix the issue accordingly. So the current version supports the idea of logical constness.
to provide only one of them, which leads to the obscure behavior just explained.<br> <br>
</p> </p>
<h3>Recommended practice: The non-member get() idiom</h3> <h3>Recommended practice: The non-member get() idiom</h3>
<p>The obscure behavior of being able to modify a non-<code>const</code> <p>The obscure behavior of being able to modify a non-<code>const</code>
wrapped object from within a constant wrapper can be avoided if access to wrapped object from within a constant wrapper (as was supported by previous
versions of <code>value_initialized</code>)
can be avoided if access to
the wrapped object is always performed with the <code>get()</code> idiom:</p> the wrapped object is always performed with the <code>get()</code> idiom:</p>
<pre>value_initialized&lt;int&gt; x ;<br>get(x) = 1 ; // OK<br><br>value_initialized&lt;int const&gt; cx ;<br>get(x) = 1 ; // ERROR: Cannot modify a const object<br><br>value_initialized&lt;int&gt; const x_c ;<br>get(x_c) = 1 ; // ERROR: Cannot modify a const object<br><br>value_initialized&lt;int const&gt; const cx_c ;<br>get(cx_c) = 1 ; // ERROR: Cannot modify a const object<br></pre> <pre>value_initialized&lt;int&gt; x ;<br>get(x) = 1 ; // OK<br><br>value_initialized&lt;int const&gt; cx ;<br>get(x) = 1 ; // ERROR: Cannot modify a const object<br><br>value_initialized&lt;int&gt; const x_c ;<br>get(x_c) = 1 ; // ERROR: Cannot modify a const object<br><br>value_initialized&lt;int const&gt; const cx_c ;<br>get(cx_c) = 1 ; // ERROR: Cannot modify a const object<br></pre>
@ -383,9 +407,9 @@ for Boost release version 1.35 (2008), offering a workaround to various compiler
</p> </p>
<hr> <hr>
<p>Revised 28 August 2008</p> <p>Revised 20 February 2009</p>
<p>&copy; Copyright Fernando Cacciola, 2002, 2008.</p> <p>&copy; Copyright Fernando Cacciola, 2002, 2009.</p>
<p>Distributed under the Boost Software License, Version 1.0. See <p>Distributed under the Boost Software License, Version 1.0. See
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a></p> <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a></p>

View File

@ -260,7 +260,7 @@ bool test ( T const& y, T const& z )
boost::value_initialized<T> const x_c ; boost::value_initialized<T> const x_c ;
BOOST_CHECK ( y == x_c ) ; BOOST_CHECK ( y == x_c ) ;
BOOST_CHECK ( y == boost::get(x_c) ) ; BOOST_CHECK ( y == boost::get(x_c) ) ;
T& x_c_ref = x_c ; T& x_c_ref = const_cast<T&>( boost::get(x_c) ) ;
x_c_ref = z ; x_c_ref = z ;
BOOST_CHECK ( x_c == z ) ; BOOST_CHECK ( x_c == z ) ;