• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<html>
2<head>
3
4  <meta http-equiv="Content-Type"
5 content="text/html; charset=iso-8859-1">
6  <title>value_initialized</title>
7
8</head>
9  <body vlink="#800080" link="#0000ff" text="#000000" bgcolor="#ffffff">
10
11<h2><img src="../../boost.png" width="276" height="86">
12         Header &lt;<a href="../../boost/utility/value_init.hpp">boost/utility/value_init.hpp</a>&gt;
13     </h2>
14
15<h2>Contents</h2>
16
17<dl>
18  <dt><a href="#rationale">Rationale</a></dt>
19  <dt><a href="#intro">Introduction</a></dt>
20  <dt><a href="#details">Details</a></dt>
21</dl>
22
23<ul>
24          <li><a href="#valueinit">value-initialization</a></li>
25          <li><a href="#valueinitsyn">value-initialization syntax</a></li>
26          <li><a href="#compiler_issues">compiler issues</a></li>
27
28</ul>
29
30<dl class="page-index">
31  <dt><a href="#types">Types and objects</a></dt>
32</dl>
33
34<ul>
35          <li><a href="#val_init"><code>template class value_initialized&lt;T&gt;</code></a></li>
36          <li><a href="#initialized"><code>template class initialized&lt;T&gt;</code></a></li>
37          <li><a href="#initialized_value"><code>initialized_value</code></a></li>
38
39</ul>
40              <a href="#acknowledgements">Acknowledgements</a><br>
41     <br>
42
43<hr>
44<h2><a name="rationale"></a>Rationale</h2>
45
46<p>Constructing and initializing objects in a generic way is difficult in
47    C++. The problem is that there are several different rules that apply
48for    initialization. Depending on the type, the value of a newly constructed
49  object  can be zero-initialized (logically 0), default-constructed (using
50  the default constructor), or indeterminate. When writing generic code,
51this  problem must be addressed. The template <code>value_initialized</code> provides
52a solution   with consistent syntax for value   initialization of scalar,
53union and class   types.
54Moreover, <code>value_initialized</code> offers a workaround to various
55compiler issues regarding value-initialization.
56
57Furthermore, a <code>const</code> object, <code>initialized_value</code> is provided,
58to avoid repeating the type name when retrieving the value from a
59<code>value_initialized&lt;T&gt;</code> object.
60<br>
61  </p>
62
63<h2><a name="intro"></a>Introduction</h2>
64
65<p>
66There are various ways to initialize a variable, in C++. The following
67declarations all <em>may</em> have a local variable initialized to its default
68value:
69<pre>
70  T1 var1;
71  T2 var2 = 0;
72  T3 var3 = {};
73  T4 var4 = T4();
74</pre>
75Unfortunately, whether or not any of those declarations correctly
76initialize the variable very much depends on its type. The first
77declaration is valid for any <a href="http://www.sgi.com/tech/stl/DefaultConstructible.html">
78DefaultConstructible</a> type (by definition).
79However, it does not always do an initialization!
80It correctly initializes the variable when it's an instance of a
81class, and the author of the class has provided a proper default
82constructor. On the other hand, the value of <code>var1</code> is <em>indeterminate</em> when
83its type is an arithmetic type, like <code>int</code>, <code>float</code>, or <code>char</code>.
84An arithmetic variable
85is of course initialized properly by the second declaration, <code>T2
86var2 = 0</code>. But this initialization form usually won't work for a
87class type (unless the class was especially written to support being
88initialized that way). The third form,  <code>T3 var3 = {}</code>
89initializes an aggregate, typically a "C-style" <code>struct</code> or a "C-style" array.
90However, the syntax is not allowed for a class that has an explicitly declared
91constructor.  (But watch out for an upcoming C++ language change,
92by Bjarne Stroustrup et al [<a href="#references">1</a>]!)
93The fourth form is the most generic form of them, as it
94can be used to initialize arithmetic types, class types, aggregates, pointers, and
95other types. The declaration,  <code>T4 var4 = T4()</code>, should be read
96as follows: First a temporary object is created, by <code>T4()</code>.
97This object is <a href="#valueinit">value-initialized</a>. Next the temporary
98object is copied to the named variable, <code>var4</code>. Afterwards, the temporary
99is destroyed. While the copying and the destruction are likely to
100be optimized away, C++ still requires the type <code>T4</code> to be
101<a href="CopyConstructible.html">CopyConstructible</a>.
102(So <code>T4</code> needs to be <em>both</em> DefaultConstructible <em>and</em> CopyConstructible.)
103A class may not be CopyConstructible, for example because it may have a
104private and undefined copy constructor,
105or because it may be derived from <a href="utility.htm#Class_noncopyable">boost::noncopyable</a>.
106Scott Meyers [<a href="#references">2</a>] explains why a class would be defined like that.
107</p>
108<p>
109There is another, less obvious disadvantage to the fourth form, <code>T4 var4 = T4()</code>:
110It suffers from various  <a href="#compiler_issues">compiler issues</a>, causing
111a variable to be left uninitialized in some compiler specific cases.
112</p>
113<p>
114The template <a href="#val_init"><code>value_initialized</code></a>
115offers a generic way to initialize
116an object, like <code>T4 var4 = T4()</code>, but without requiring its type
117to be CopyConstructible. And it offers a workaround to those compiler issues
118regarding value-initialization as well! It allows getting an initialized
119variable of any type; it <em>only</em> requires the type to be DefaultConstructible.
120A properly <em>value-initialized</em> object of type <code>T</code> is
121constructed by the following declaration:
122<pre>
123  value_initialized&lt;T&gt; var;
124</pre>
125</p>
126<p>
127The template <a href="#initialized"><code>initialized</code></a>
128offers both value-initialization and direct-initialization.
129It is especially useful as a data member type, allowing the very same object
130to be either direct-initialized or value-initialized.
131</p>
132<p>
133The <code>const</code> object <a href="#initialized_value"><code>initialized_value</code></a>
134allows value-initializing a variable as follows:
135<pre>
136  T var = initialized_value ;
137</pre>
138This form of initialization is semantically equivalent to <code>T4 var4 = T4()</code>,
139but robust against the aforementioned compiler issues.
140
141</p>
142
143<h2><a name="details"></a>Details</h2>
144<p>The C++ standard [<a href="#references">3</a>] contains the definitions
145    of <code>zero-initialization</code> and <code>default-initialization</code>.
146     Informally, zero-initialization means that the object is given the initial
147     value 0 (converted to the type) and default-initialization means that
148 POD   [<a href="#references">4</a>] types are zero-initialized, while non-POD class
149 types   are initialized with their corresponding default constructors. A
150<i>declaration</i>   can contain an <i>initializer</i>, which specifies the
151object's initial value.  The initializer can be just '()', which states that
152the object shall be value-initialized  (but see below). However, if a <i>declaration</i>
153  has no <i>initializer</i>  and it is of a non-<code>const</code>, non-<code>static</code>
154   POD type, the initial value is indeterminate: <cite>(see &sect;8.5, [dcl.init], for the
155   accurate definitions).</cite></p>
156
157<pre>int x ; // no initializer. x value is indeterminate.<br>std::string s ; // no initializer, s is default-constructed.<br><br>int y = int() ; <br>// y is initialized using copy-initialization<br>// but the temporary uses an empty set of parentheses as the initializer,<br>// so it is default-constructed.<br>// A default constructed POD type is zero-initialized,<br>// therefore, y == 0.<br><br>void foo ( std::string ) ;<br>foo ( std::string() ) ; <br>// the temporary string is default constructed <br>// as indicated by the initializer ()  </pre>
158
159<h3><a name="valueinit">value-initialization</a></h3>
160
161<p>The first <a
162 href="http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html">Technical
163  Corrigendum for the C++ Standard</a> (TC1), whose draft   was released to
164  the public in November 2001, introduced <a
165 href="http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#178">Core
166  Issue 178</a> (among   many other issues, of course).</p>
167
168<p> That issue introduced the new concept of <code>value-initialization</code>
169     (it also fixed the wording for zero-initialization). Informally, value-initialization
170    is similar to default-initialization with the exception that in some cases
171    non-static data members and base class sub-objects are also value-initialized.
172    The difference is that an object that is value-initialized won't have
173(or    at least is less likely to have) indeterminate values for data members
174 and   base class sub-objects; unlike the case of an object default constructed.
175    (see Core Issue 178 for a normative description).</p>
176
177<p>In order to specify value-initialization of an object we need to use the
178     empty-set initializer: (). </p>
179
180<p>As before, a declaration with no intializer specifies default-initialization,
181    and a declaration with a non-empty initializer specifies copy (=xxx) or
182  direct  (xxx) initialization. </p>
183
184<pre>template&lt;class T&gt; void eat(T);<br>int x ; // indeterminate initial value.<br>std::string s; // default-initialized.<br>eat ( int() ) ; // value-initialized<br>eat ( std::string() ) ; // value-initialized</pre>
185
186<h4><a name="valueinitsyn">value-initialization</a> syntax</h4>
187
188<p>Value initialization is specified using (). However, the empty set of
189parentheses is not permitted by the syntax of initializers because it is
190parsed as the declaration of a function taking no arguments: </p>
191
192<pre>int x() ; // declares function int(*)()</pre>
193
194<p>Thus, the empty () must be put in some other initialization context.</p>
195
196<p>One alternative is to use copy-initialization syntax:</p>
197
198<pre>int x = int() ;</pre>
199
200<p>This works perfectly fine for POD types. But for non-POD class types,
201copy-initialization searches for a suitable constructor, which could be,
202for instance, the copy-constructor (it also searches for a suitable conversion
203sequence but this doesn't apply in this context). For an arbitrary unknown
204type, using this syntax may not have the value-initialization effect intended
205because we don't know if a copy from a default constructed object is exactly
206the same as a default constructed object, and the compiler is allowed (in
207some cases), but never required to, optimize the copy away.</p>
208
209<p>One possible generic solution is to use value-initialization of a non static
210data member:</p>
211
212<pre>template&lt;class T&gt; <br>struct W <br>{<br>  // value-initialization of 'data' here.<br>  W() : data() {}<br>  T data ;<br>} ;<br>W&lt;int&gt; w ;<br>// w.data is value-initialized for any type. </pre>
213
214<p>This is the solution as it was supplied by earlier versions of the
215<code>value_initialized&lt;T&gt;</code> template
216     class. Unfortunately this approach suffered from various compiler issues.</p>
217
218<h4><a name="compiler_issues">compiler issues</a> </h4>
219
220Various compilers haven't yet fully implemented value-initialization.
221So when an object should be <em>value-initialized</em> (according to the C++ Standard),
222it <em>may</em> in practice still be left uninitialized, because of those
223compiler issues! It's hard to make a general statement on what those issues
224are like, because they depend on the compiler you are using, its version number,
225and the type of object you would like to have value-initialized.
226All compilers we have tested so far support value-initialization for arithmetic types properly.
227However, various compilers may leave some types of <em>aggregates</em> uninitialized, when they
228should be value-initialized. Value-initialization of objects of a pointer-to-member type may also
229go wrong on various compilers.
230</p>
231<p>
232At the moment of writing, May 2010, the following reported issues regarding
233value-initialization are still there in current compiler releases:
234<ul>
235<li>
236<a href="https://connect.microsoft.com/VisualStudio/feedback/details/100744">
237Microsoft Visual Studio Feedback ID 100744, Value-initialization in new-expression</a>
238<br>Reported by Pavel Kuznetsov (MetaCommunications Engineering), 2005
239</li><li>
240<a href="http://connect.microsoft.com/VisualStudio/feedback/details/484295">
241Microsoft Visual Studio Feedback ID 484295, VC++ does not value-initialize members of derived classes without user-declared constructor</a>
242<br>Reported by Sylvester Hesp, 2009
243</li><li>
244<a href="https://connect.microsoft.com/VisualStudio/feedback/details/499606">
245Microsoft Visual Studio Feedback ID 499606, Presence of copy constructor breaks member class initialization</a>
246<br>Reported by Alex Vakulenko, 2009
247</li><li>
248<a href="http://qc.embarcadero.com/wc/qcmain.aspx?d=83751">
249Embarcadero/C++Builder Report 83751, Value-initialization: arrays should have each element value-initialized</a>
250<br>Reported by Niels Dekker (LKEB), 2010
251</li><li>
252<a href="http://qc.embarcadero.com/wc/qcmain.aspx?d=83851">
253Embarcadero/C++Builder Report 83851, Value-initialized temporary triggers internal backend error C1798</a>
254<br>Reported by Niels Dekker, 2010
255</li><li>
256<a href="http://qc.embarcadero.com/wc/qcmain.aspx?d=84279">
257Embarcadero/C++Builder Report 84279, Internal compiler error (F1004), value-initializing member function pointer by "new T()"</a>
258<br>Reported by Niels Dekker, 2010
259</li><li>
260Sun CR 6947016, Sun 5.10 may fail to value-initialize an object of a non-POD aggregate.
261<br>Reported to Steve Clamage by Niels Dekker, 2010
262</li><li>
263IBM's XL V10.1 and V11.1 may fail to value-initialize a temporary of a non-POD aggregate.
264<br>Reported to Michael Wong by Niels Dekker, 2010
265</li><li>
266Intel support issue 589832, Attempt to value-initialize pointer-to-member triggers internal error
267on Intel 11.1.
268<br>Reported by John Maddock, 2010
269</li>
270</ul>
271Note that all known GCC issues regarding value-initialization are
272fixed with GCC version 4.4, including
273<a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30111">GCC Bug 30111</a>.
274Clang also has completely implemented value-initialization, as far as we know,
275now that <a href="http://llvm.org/bugs/show_bug.cgi?id=7139">Clang Bug 7139</a> is fixed.
276</p><p>
277
278New versions of <code>value_initialized</code>
279(Boost release version 1.35 or higher)
280offer a workaround to these issues: <code>value_initialized</code> may now clear
281its internal data, prior to constructing the object that it contains. It will do
282so for those compilers that need to have such a workaround, based on the
283<a href="../config/doc/html/boost_config/boost_macro_reference.html#boost_config.boost_macro_reference.macros_that_describe_defects"
284>compiler defect macro</a> BOOST_NO_COMPLETE_VALUE_INITIALIZATION.
285</p>
286
287<h2><a name="types"></a>Types and objects</h2>
288
289<h2><a name="val_init"><code>template class value_initialized&lt;T&gt;</code></a></h2>
290
291<pre>namespace boost {<br><br>template&lt;class T&gt;<br>class value_initialized<br>{
292<br>  public :
293<br>    value_initialized() : x() {}
294<br>    operator T const &amp;() const { return x ; }
295<br>    operator T&amp;() { return x ; }
296<br>    T const &amp;data() const { return x ; }
297<br>    T&amp; data() { return x ; }
298<br>    void swap( value_initialized&amp; );
299<br>
300<br>  private :
301<br>    <i>unspecified</i> x ;
302<br>} ;
303<br>
304<br>template&lt;class T&gt;
305<br>T const&amp; get ( value_initialized&lt;T&gt; const&amp; x )
306<br>{
307<br>  return x.data() ;
308<br>}
309<br>
310<br>template&lt;class T&gt;
311<br>T&amp; get ( value_initialized&lt;T&gt;&amp; x )
312<br>{
313<br>  return x.data() ;
314<br>}
315<br>
316<br>template&lt;class T&gt;
317<br>void swap ( value_initialized&lt;T&gt;&amp; lhs, value_initialized&lt;T&gt;&amp; rhs )
318<br>{
319<br>  lhs.swap(rhs) ;
320<br>}
321<br>
322<br>} // namespace boost
323<br></pre>
324
325<p>An object of this template class is a <code>T</code>-wrapper convertible
326    to <code>'T&amp;'</code> whose wrapped object (data member of type <code>T</code>)
327    is <a href="#valueinit">value-initialized</a> upon default-initialization
328    of this wrapper class: </p>
329
330<pre>int zero = 0 ;<br>value_initialized&lt;int&gt; x ;<br>assert ( x == zero ) ;<br><br>std::string def ;<br>value_initialized&lt; std::string &gt; y ;<br>assert ( y == def ) ;<br></pre>
331
332<p>The purpose of this wrapper is to provide a consistent syntax for value
333     initialization of scalar, union and class types (POD and non-POD) since
334   the  correct syntax for value initialization varies (see <a
335 href="#valueinitsyn">value-initialization syntax</a>)</p>
336
337<p>The wrapped object can be accessed either through the conversion operator
338     <code>T&amp;</code>, the member function <code>data()</code>, or the
339non-member    function <code>get()</code>:  </p>
340
341<pre>void watch(int);<br>value_initialized&lt;int&gt; x;
342<br><br>watch(x) ; // operator T&amp; used.<br>watch(x.data());<br>watch( get(x) ) // function get() used</pre>
343
344<p>Both <code>const</code> and non-<code>const</code> objects can be wrapped.
345    Mutable objects can be modified directly from within the wrapper but constant
346    objects cannot:</p>
347
348<p>When <code>T</code> is a <em>Swappable</em> type, <code>value_initialized&lt;T&gt;</code>
349    is swappable as well, by calling its <code>swap</code> member function
350    as well as by calling <code>boost::swap</code>.</p>
351
352<pre>value_initialized&lt;int&gt; x ; <br>static_cast&lt;int&amp;&gt;(x) = 1 ; // OK<br>get(x) = 1 ; // OK
353<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>
354
355<h3>Warning:</h3>
356
357<p>The <code>value_initialized</code> implementation of Boost version 1.40.0 and older
358allowed <i>non-const</i> access to the wrapped object, from a constant wrapper,
359both by its conversion operator and its <code>data()</code> member function. For example:</p>
360
361<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.
362<br>xr = 2 ; </pre>
363
364<p>The reason for this obscure behavior was that some compilers
365     didn't accept the following valid code:</p>
366
367<pre>struct X<br>{<br>  operator int&amp;() ;<br>  operator int const&amp;() const ;   <br>};<br>X x ;<br>(x == 1 ) ; // ERROR HERE!</pre>
368
369<p>The current version of <code>value_initialized</code> no longer has this obscure behavior.
370As 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.
371<br>
372          </p>
373
374<h3>Recommended practice: The non-member get() idiom</h3>
375
376<p>The obscure behavior of being able to modify a non-<code>const</code>
377wrapped object from within a constant wrapper (as was supported by previous
378versions of <code>value_initialized</code>)
379can be avoided if access to
380the wrapped object is always performed with the <code>get()</code> idiom:</p>
381
382<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
384<h2><a name="initialized"><code>template class initialized&lt;T&gt;</code></a></h2>
385
386<pre>namespace boost {<br><br>template&lt;class T&gt;<br>class initialized<br>{
387<br>  public :
388<br>    initialized() : x() {}
389<br>    explicit initialized(T const &amp; arg) : x(arg) {}
390<br>    operator T const &amp;() const;
391<br>    operator T&amp;();
392<br>    T const &amp;data() const;
393<br>    T&amp; data();
394<br>    void swap( initialized&amp; );
395<br>
396<br>  private :
397<br>    <i>unspecified</i> x ;
398<br>} ;
399<br>
400<br>template&lt;class T&gt;
401<br>T const&amp; get ( initialized&lt;T&gt; const&amp; x );
402<br>
403<br>template&lt;class T&gt;
404<br>T&amp; get ( initialized&lt;T&gt;&amp; x );
405<br>
406<br>template&lt;class T&gt;
407<br>void swap ( initialized&lt;T&gt;&amp; lhs, initialized&lt;T&gt;&amp; rhs );
408<br>
409<br>} // namespace boost
410<br></pre>
411
412The template class <code>boost::initialized&lt;T&gt;</code> supports both value-initialization
413and direct-initialization, so its interface is a superset of the interface
414of <code>value_initialized&lt;T&gt;</code>: Its default-constructor
415value-initializes the wrapped object just like the default-constructor of
416<code>value_initialized&lt;T&gt;</code>, but <code>boost::initialized&lt;T&gt;</code>
417also offers an extra <code>explicit</code>
418constructor, which direct-initializes the wrapped object by the specified value.
419<p>
420
421<code>initialized&lt;T&gt;</code> is especially useful when the wrapped
422object must be either value-initialized or direct-initialized, depending on
423runtime conditions. For example, <code>initialized&lt;T&gt;</code> could
424hold the value of a data member that may be value-initialized by some
425constructors, and direct-initialized by others.
426On the other hand, if it is known beforehand that the
427object must <i>always</i> be value-initialized, <code>value_initialized&lt;T&gt;</code>
428may be preferable. And if the object must always be
429direct-initialized, none of the two wrappers really needs to be used.
430</p>
431
432
433<h2><a name="initialized_value"><code>initialized_value</code></a></h2>
434
435<pre>
436namespace boost {
437class initialized_value_t
438{
439  public :
440    template &lt;class T&gt; operator T() const ;
441};
442
443initialized_value_t const initialized_value = {} ;
444
445} // namespace boost
446</pre>
447
448<code>initialized_value</code> provides a convenient way to get
449an initialized value: its conversion operator provides an appropriate
450<em>value-initialized</em> object for any CopyConstructible type.
451
452Suppose you need to have an initialized variable of type <code>T</code>.
453You could do it as follows:
454<pre>
455  T var = T();
456</pre>
457But as mentioned before, this form suffers from various compiler issues.
458The template <code>value_initialized</code> offers a workaround:
459<pre>
460  T var = get( value_initialized&lt;T&gt;() );
461</pre>
462Unfortunately both forms repeat the type name, which
463is rather short now (<code>T</code>), but could of course be
464more like <code>Namespace::Template&lt;Arg&gt;::Type</code>.
465Instead, one could use <code>initialized_value</code> as follows:
466<pre>
467  T var = initialized_value ;
468</pre>
469
470<h3><a name="references">References</a></h3>
471          [1] Bjarne Stroustrup, Gabriel Dos Reis, and J. Stephen Adamczyk wrote
472          various papers, proposing to extend the support for brace-enclosed <em>initializer lists</em>
473          in the next version of C++.
474          This would allow a variable <code>var</code> of any DefaultConstructible type
475          <code>T</code> to be <em>value-initialized</em> by doing <code>T var = {}</code>.
476          The papers are listed at Bjarne's web page,
477          <a href="http://www.research.att.com/~bs/WG21.html">My C++ Standards committee papers</a>  <br>
478          [2] Scott Meyers, Effective C++, Third Edition, item 6,
479          <em>Explicitly disallow the use of compiler-generated functions you do not want</em>,
480          <a href="http://www.aristeia.com/books.html">Scott Meyers: Books and CDs</a>  <br>
481          [3] The C++ Standard, Second edition (2003), ISO/IEC 14882:2003 <br>
482          [4] POD stands for "Plain Old Data"
483
484<h3><a name="acknowledgements"></a>Acknowledgements</h3>
485     value_initialized was developed by Fernando Cacciola, with help and
486suggestions from David Abrahams and Darin Adler.<br>
487Special thanks to Bj&ouml;rn Karlsson who carefully edited and completed this documentation.
488
489<p>value_initialized was reimplemented by Fernando Cacciola and Niels Dekker
490for Boost release version 1.35 (2008), offering a workaround to various compiler issues.
491     </p>
492<p><code>boost::initialized</code> was very much inspired by feedback from Edward Diener and
493  Jeffrey Hellrung.
494     </p>
495<p>initialized_value was written by Niels Dekker, and added to Boost release version 1.36 (2008).
496     </p>
497<p>Developed by <a href="mailto:fernando_cacciola@hotmail.com">Fernando Cacciola</a>,
498     the latest version of this file can be found at <a
499 href="http://www.boost.org">www.boost.org</a>.
500     </p>
501
502<hr>
503<p>Revised 30 May 2010</p>
504
505<p>&copy; Copyright Fernando Cacciola, 2002 - 2010.</p>
506
507<p>Distributed under the Boost Software License, Version 1.0. See
508<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a></p>
509
510 <br>
511 <br>
512
513</body>
514</html>
515