diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/utility/call_traits.htm | |
parent | Initial commit. (diff) | |
download | ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.tar.xz ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/utility/call_traits.htm')
-rw-r--r-- | src/boost/libs/utility/call_traits.htm | 755 |
1 files changed, 755 insertions, 0 deletions
diff --git a/src/boost/libs/utility/call_traits.htm b/src/boost/libs/utility/call_traits.htm new file mode 100644 index 00000000..b4fe3ee9 --- /dev/null +++ b/src/boost/libs/utility/call_traits.htm @@ -0,0 +1,755 @@ +<html> + +<head> +<meta http-equiv="Content-Type" +content="text/html; charset=iso-8859-1"> +<meta name="Template" +content="C:\PROGRAM FILES\MICROSOFT OFFICE\OFFICE\html.dot"> +<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0"> +<title>Call Traits</title> +</head> + +<body bgcolor="#FFFFFF" text="#000000" link="#0000FF" +vlink="#800080"> + +<h1><img src="../../boost.png" width="276" height="86">Header +<<a href="../../boost/detail/call_traits.hpp">boost/call_traits.hpp</a>></h1> + +<p>All of the contents of <boost/call_traits.hpp> are +defined inside namespace boost.</p> + +<p>The template class call_traits<T> encapsulates the +"best" method to pass a parameter of some type T to or +from a function, and consists of a collection of typedefs defined +as in the table below. The purpose of call_traits is to ensure +that problems like "<a href="#refs">references to references</a>" +never occur, and that parameters are passed in the most efficient +manner possible (see <a href="#examples">examples</a>). In each +case if your existing practice is to use the type defined on the +left, then replace it with the call_traits defined type on the +right. </p> + +<p>Note that for compilers that do not support either partial +specialization or member templates, no benefit will occur from +using call_traits: the call_traits defined types will always be +the same as the existing practice in this case. In addition if +only member templates and not partial template specialisation is +support by the compiler (for example Visual C++ 6) then +call_traits can not be used with array types (although it can be +used to solve the reference to reference problem).</p> + +<table border="0" cellpadding="7" cellspacing="1" width="797"> + <tr> + <td valign="top" width="17%" bgcolor="#008080"><p + align="center">Existing practice</p> + </td> + <td valign="top" width="35%" bgcolor="#008080"><p + align="center">call_traits equivalent</p> + </td> + <td valign="top" width="32%" bgcolor="#008080"><p + align="center">Description</p> + </td> + <td valign="top" width="16%" bgcolor="#008080"><p + align="center">Notes</p> + </td> + </tr> + <tr> + <td valign="top" width="17%"><p align="center">T<br> + (return by value)</p> + </td> + <td valign="top" width="35%"><p align="center"><code>call_traits<T>::value_type</code></p> + </td> + <td valign="top" width="32%">Defines a type that + represents the "value" of type T. Use this for + functions that return by value, or possibly for stored + values of type T.</td> + <td valign="top" width="16%"><p align="center">2</p> + </td> + </tr> + <tr> + <td valign="top" width="17%"><p align="center">T&<br> + (return value)</p> + </td> + <td valign="top" width="35%"><p align="center"><code>call_traits<T>::reference</code></p> + </td> + <td valign="top" width="32%">Defines a type that + represents a reference to type T. Use for functions that + would normally return a T&.</td> + <td valign="top" width="16%"><p align="center">1</p> + </td> + </tr> + <tr> + <td valign="top" width="17%"><p align="center">const + T&<br> + (return value)</p> + </td> + <td valign="top" width="35%"><p align="center"><code>call_traits<T>::const_reference</code></p> + </td> + <td valign="top" width="32%">Defines a type that + represents a constant reference to type T. Use for + functions that would normally return a const T&.</td> + <td valign="top" width="16%"><p align="center">1</p> + </td> + </tr> + <tr> + <td valign="top" width="17%"><p align="center">const + T&<br> + (function parameter)</p> + </td> + <td valign="top" width="35%"><p align="center"><code>call_traits<T>::param_type</code></p> + </td> + <td valign="top" width="32%">Defines a type that + represents the "best" way to pass a parameter + of type T to a function.</td> + <td valign="top" width="16%"><p align="center">1,3</p> + </td> + </tr> +</table> + +<p>Notes:</p> + +<ol> + <li>If T is already reference type, then call_traits is + defined such that <a href="#refs">references to + references</a> do not occur (requires partial + specialization).</li> + <li>If T is an array type, then call_traits defines <code>value_type</code> + as a "constant pointer to type" rather than an + "array of type" (requires partial + specialization). Note that if you are using value_type as + a stored value then this will result in storing a "constant + pointer to an array" rather than the array itself. + This may or may not be a good thing depending upon what + you actually need (in other words take care!).</li> + <li>If T is a small built in type or a pointer, then <code>param_type</code> + is defined as <code>T const</code>, instead of <code>T + const&</code>. This can improve the ability of the + compiler to optimize loops in the body of the function if + they depend upon the passed parameter, the semantics of + the passed parameter is otherwise unchanged (requires + partial specialization).</li> +</ol> + +<p> </p> + +<h3>Copy constructibility</h3> + +<p>The following table defines which call_traits types can always +be copy-constructed from which other types, those entries marked +with a '?' are true only if and only if T is copy constructible:</p> + +<table border="0" cellpadding="7" cellspacing="1" width="766"> + <tr> + <td valign="top" width="17%"> </td> + <td valign="top" colspan="5" width="85%" + bgcolor="#008080"><p align="center">To:</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#008080">From:</td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">T</p> + </td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">value_type</p> + </td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">reference</p> + </td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">const_reference</p> + </td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">param_type</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0">T</td> + <td valign="top" width="17%"><p align="center">?</p> + </td> + <td valign="top" width="17%"><p align="center">?</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0">value_type</td> + <td valign="top" width="17%"><p align="center">?</p> + </td> + <td valign="top" width="17%"><p align="center">?</p> + </td> + <td valign="top" width="17%"><p align="center">N</p> + </td> + <td valign="top" width="17%"><p align="center">N</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0">reference</td> + <td valign="top" width="17%"><p align="center">?</p> + </td> + <td valign="top" width="17%"><p align="center">?</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0">const_reference</td> + <td valign="top" width="17%"><p align="center">?</p> + </td> + <td valign="top" width="17%"><p align="center">N</p> + </td> + <td valign="top" width="17%"><p align="center">N</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0">param_type</td> + <td valign="top" width="17%"><p align="center">?</p> + </td> + <td valign="top" width="17%"><p align="center">?</p> + </td> + <td valign="top" width="17%"><p align="center">N</p> + </td> + <td valign="top" width="17%"><p align="center">N</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + </tr> +</table> + +<p> </p> + +<p>If T is an assignable type the following assignments are +possible:</p> + +<table border="0" cellpadding="7" cellspacing="1" width="766"> + <tr> + <td valign="top" width="17%"> </td> + <td valign="top" colspan="5" width="85%" + bgcolor="#008080"><p align="center">To:</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#008080">From:</td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">T</p> + </td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">value_type</p> + </td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">reference</p> + </td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">const_reference</p> + </td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">param_type</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0">T</td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0">value_type</td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0">reference</td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0">const_reference</td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0">param_type</td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">Y</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + <td valign="top" width="17%"><p align="center">-</p> + </td> + </tr> +</table> + +<p> </p> + +<h3><a name="examples"></a>Examples</h3> + +<p>The following table shows the effect that call_traits has on +various types, the table assumes that the compiler supports +partial specialization: if it doesn't then all types behave in +the same way as the entry for "myclass", and +call_traits can not be used with reference or array types.</p> + +<table border="0" cellpadding="7" cellspacing="1" width="766"> + <tr> + <td valign="top" width="17%"> </td> + <td valign="top" colspan="5" width="85%" + bgcolor="#008080"><p align="center">Call_traits type:</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#008080"><p + align="center">Original type T</p> + </td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">value_type</p> + </td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">reference</p> + </td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">const_reference</p> + </td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">param_type</p> + </td> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">Applies to:</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">myclass</p> + </td> + <td valign="top" width="17%"><p align="center">myclass</p> + </td> + <td valign="top" width="17%"><p align="center">myclass&</p> + </td> + <td valign="top" width="17%"><p align="center">const + myclass&</p> + </td> + <td valign="top" width="17%"><p align="center">myclass + const&</p> + </td> + <td valign="top" width="17%"><p align="center">All user + defined types.</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">int</p> + </td> + <td valign="top" width="17%"><p align="center">int</p> + </td> + <td valign="top" width="17%"><p align="center">int&</p> + </td> + <td valign="top" width="17%"><p align="center">const + int&</p> + </td> + <td valign="top" width="17%"><p align="center">int const</p> + </td> + <td valign="top" width="17%"><p align="center">All small + built-in types.</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">int*</p> + </td> + <td valign="top" width="17%"><p align="center">int*</p> + </td> + <td valign="top" width="17%"><p align="center">int*&</p> + </td> + <td valign="top" width="17%"><p align="center">int*const&</p> + </td> + <td valign="top" width="17%"><p align="center">int* const</p> + </td> + <td valign="top" width="17%"><p align="center">All + pointer types.</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">int&</p> + </td> + <td valign="top" width="17%"><p align="center">int&</p> + </td> + <td valign="top" width="17%"><p align="center">int&</p> + </td> + <td valign="top" width="17%"><p align="center">const + int&</p> + </td> + <td valign="top" width="17%"><p align="center">int&</p> + </td> + <td valign="top" width="17%"><p align="center">All + reference types.</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">const int&</p> + </td> + <td valign="top" width="17%"><p align="center">const + int&</p> + </td> + <td valign="top" width="17%"><p align="center">const + int&</p> + </td> + <td valign="top" width="17%"><p align="center">const + int&</p> + </td> + <td valign="top" width="17%"><p align="center">const + int&</p> + </td> + <td valign="top" width="17%"><p align="center">All + constant-references.</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">int[3]</p> + </td> + <td valign="top" width="17%"><p align="center">const int*</p> + </td> + <td valign="top" width="17%"><p align="center">int(&)[3]</p> + </td> + <td valign="top" width="17%"><p align="center">const int(&)[3]</p> + </td> + <td valign="top" width="17%"><p align="center">const int* + const</p> + </td> + <td valign="top" width="17%"><p align="center">All array + types.</p> + </td> + </tr> + <tr> + <td valign="top" width="17%" bgcolor="#C0C0C0"><p + align="center">const int[3]</p> + </td> + <td valign="top" width="17%"><p align="center">const int*</p> + </td> + <td valign="top" width="17%"><p align="center">const int(&)[3]</p> + </td> + <td valign="top" width="17%"><p align="center">const int(&)[3]</p> + </td> + <td valign="top" width="17%"><p align="center">const int* + const</p> + </td> + <td valign="top" width="17%"><p align="center">All + constant-array types.</p> + </td> + </tr> +</table> + +<p> </p> + +<h4>Example 1:</h4> + +<p>The following class is a trivial class that stores some type T +by value (see the <a href="test/call_traits_test.cpp">call_traits_test.cpp</a> +file), the aim is to illustrate how each of the available +call_traits typedefs may be used:</p> + +<pre>template <class T> +struct contained +{ + // define our typedefs first, arrays are stored by value + // so value_type is not the same as result_type: + typedef typename boost::call_traits<T>::param_type param_type; + typedef typename boost::call_traits<T>::reference reference; + typedef typename boost::call_traits<T>::const_reference const_reference; + typedef T value_type; + typedef typename boost::call_traits<T>::value_type result_type; + + // stored value: + value_type v_; + + // constructors: + contained() {} + contained(param_type p) : v_(p){} + // return byval: + result_type value() { return v_; } + // return by_ref: + reference get() { return v_; } + const_reference const_get()const { return v_; } + // pass value: + void call(param_type p){} + +};</pre> + +<h4><a name="refs"></a>Example 2 (the reference to reference +problem):</h4> + +<p>Consider the definition of std::binder1st:</p> + +<pre>template <class Operation> +class binder1st : + public unary_function<typename Operation::second_argument_type, typename Operation::result_type> +{ +protected: + Operation op; + typename Operation::first_argument_type value; +public: + binder1st(const Operation& x, const typename Operation::first_argument_type& y); + typename Operation::result_type operator()(const typename Operation::second_argument_type& x) const; +}; </pre> + +<p>Now consider what happens in the relatively common case that +the functor takes its second argument as a reference, that +implies that <code>Operation::second_argument_type</code> is a +reference type, <code>operator()</code> will now end up taking a +reference to a reference as an argument, and that is not +currently legal. The solution here is to modify <code>operator()</code> +to use call_traits:</p> + +<pre>typename Operation::result_type operator()(typename call_traits<typename Operation::second_argument_type>::param_type x) const;</pre> + +<p>Now in the case that <code>Operation::second_argument_type</code> +is a reference type, the argument is passed as a reference, and +the no "reference to reference" occurs.</p> + +<h4><a name="ex3"></a>Example 3 (the make_pair problem):</h4> + +<p>If we pass the name of an array as one (or both) arguments to <code>std::make_pair</code>, +then template argument deduction deduces the passed parameter as +"const reference to array of T", this also applies to +string literals (which are really array literals). Consequently +instead of returning a pair of pointers, it tries to return a +pair of arrays, and since an array type is not copy-constructible +the code fails to compile. One solution is to explicitly cast the +arguments to make_pair to pointers, but call_traits provides a +better (i.e. automatic) solution (and one that works safely even +in generic code where the cast might do the wrong thing):</p> + +<pre>template <class T1, class T2> +std::pair< + typename boost::call_traits<T1>::value_type, + typename boost::call_traits<T2>::value_type> + make_pair(const T1& t1, const T2& t2) +{ + return std::pair< + typename boost::call_traits<T1>::value_type, + typename boost::call_traits<T2>::value_type>(t1, t2); +}</pre> + +<p>Here, the deduced argument types will be automatically +degraded to pointers if the deduced types are arrays, similar +situations occur in the standard binders and adapters: in +principle in any function that "wraps" a temporary +whose type is deduced. Note that the function arguments to +make_pair are not expressed in terms of call_traits: doing so +would prevent template argument deduction from functioning.</p> + +<h4><a name="ex4"></a>Example 4 (optimising fill):</h4> + +<p>The call_traits template will "optimize" the passing +of a small built-in type as a function parameter, this mainly has +an effect when the parameter is used within a loop body. In the +following example (see <a +href="../type_traits/examples/fill_example.cpp">fill_example.cpp</a>), +a version of std::fill is optimized in two ways: if the type +passed is a single byte built-in type then std::memset is used to +effect the fill, otherwise a conventional C++ implemention is +used, but with the passed parameter "optimized" using +call_traits:</p> + +<pre>namespace detail{ + +template <bool opt> +struct filler +{ + template <typename I, typename T> + static void do_fill(I first, I last, typename boost::call_traits<T>::param_type val) + { + while(first != last) + { + *first = val; + ++first; + } + } +}; + +template <> +struct filler<true> +{ + template <typename I, typename T> + static void do_fill(I first, I last, T val) + { + memset(first, val, last-first); + } +}; + +} + +template <class I, class T> +inline void fill(I first, I last, const T& val) +{ + enum{ can_opt = boost::is_pointer<I>::value + && boost::is_arithmetic<T>::value + && (sizeof(T) == 1) }; + typedef detail::filler<can_opt> filler_t; + filler_t::template do_fill<I,T>(first, last, val); +}</pre> + +<p>Footnote: the reason that this is "optimal" for +small built-in types is that with the value passed as "T +const" instead of "const T&" the compiler is +able to tell both that the value is constant and that it is free +of aliases. With this information the compiler is able to cache +the passed value in a register, unroll the loop, or use +explicitly parallel instructions: if any of these are supported. +Exactly how much mileage you will get from this depends upon your +compiler - we could really use some accurate benchmarking +software as part of boost for cases like this.</p> + +<p>Note that the function arguments to fill are not expressed in +terms of call_traits: doing so would prevent template argument +deduction from functioning. Instead fill acts as a "thin +wrapper" that is there to perform template argument +deduction, the compiler will optimise away the call to fill all +together, replacing it with the call to filler<>::do_fill, +which does use call_traits.</p> + +<h3>Rationale</h3> + +<p>The following notes are intended to briefly describe the +rational behind choices made in call_traits.</p> + +<p>All user-defined types follow "existing practice" +and need no comment.</p> + +<p>Small built-in types (what the standard calls fundamental +types [3.9.1]) differ from existing practice only in the <i>param_type</i> +typedef. In this case passing "T const" is compatible +with existing practice, but may improve performance in some cases +(see <a href="#ex4">Example 4</a>), in any case this should never +be any worse than existing practice.</p> + +<p>Pointers follow the same rational as small built-in types.</p> + +<p>For reference types the rational follows <a href="#refs">Example +2</a> - references to references are not allowed, so the +call_traits members must be defined such that these problems do +not occur. There is a proposal to modify the language such that +"a reference to a reference is a reference" (issue #106, +submitted by Bjarne Stroustrup), call_traits<T>::value_type +and call_traits<T>::param_type both provide the same effect +as that proposal, without the need for a language change (in +other words it's a workaround).</p> + +<p>For array types, a function that takes an array as an argument +will degrade the array type to a pointer type: this means that +the type of the actual parameter is different from its declared +type, something that can cause endless problems in template code +that relies on the declared type of a parameter. For example:</p> + +<pre>template <class T> +struct A +{ + void foo(T t); +};</pre> + +<p><font face="Times New Roman">In this case if we instantiate +A<int[2]> then the declared type of the parameter passed to +member function foo is int[2], but it's actual type is const int*, +if we try to use the type T within the function body, then there +is a strong likelyhood that our code will not compile:</font></p> + +<pre>template <class T> +void A<T>::foo(T t) +{ + T dup(t); // doesn't compile for case that T is an array. +}</pre> + +<p>By using call_traits the degradation from array to pointer is +explicit, and the type of the parameter is the same as it's +declared type:</p> + +<pre>template <class T> +struct A +{ + void foo(typename call_traits<T>::value_type t); +}; + +template <class T> +void A<T>::foo(typename call_traits<T>::value_type t) +{ + typename call_traits<T>::value_type dup(t); // OK even if T is an array type. +}</pre> + +<p>For value_type (return by value), again only a pointer may be +returned, not a copy of the whole array, and again call_traits +makes the degradation explicit. The value_type member is useful +whenever an array must be explicitly degraded to a pointer - <a +href="#ex3">Example 3</a> provides the test case (Footnote: the +array specialisation for call_traits is the least well understood +of all the call_traits specialisations, if the given semantics +cause specific problems for you, or don't solve a particular +array-related problem, then I would be interested to hear about +it. Most people though will probably never need to use this +specialisation).</p> + +<hr> + +<p>Revised 01 September 2000</p> + + <p> + Copyright 2000 Steve Cleary, Beman Dawes, Howard + Hinnant and John Maddock. <br/> + Use, modification and distribution are subject to the + Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt + or copy at <a href="http://www.boost.org/LICENSE_1_0.txt"> + http://www.boost.org/LICENSE_1_0.txt + </a>). + </p> +</body> +</html> + |