forked from boostorg/type_traits
Fix up docs to point to new BoostBook versions.
[SVN r28460]
This commit is contained in:
@@ -1,590 +1,15 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type"
|
||||
content="text/html; charset=iso-8859-1">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
|
||||
<title>C++ Type traits</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" link="#0000FF" vlink="#800080">
|
||||
|
||||
<h2 align="center">C++ Type traits</h2>
|
||||
|
||||
<p align="center"><em>by John Maddock and Steve Cleary</em></p>
|
||||
|
||||
<p align="center"><em>This is the draft version of an article
|
||||
that appeared in the October 2000 issue of </em><a
|
||||
href="http://www.ddj.com"><em>Dr Dobb's Journal</em></a></p>
|
||||
|
||||
<p>Generic programming (writing code which works with any data
|
||||
type meeting a set of requirements) has become the method of
|
||||
choice for providing reusable code. However, there are times in
|
||||
generic programming when "generic" just isn't good
|
||||
enough - sometimes the differences between types are too large
|
||||
for an efficient generic implementation. This is when the traits
|
||||
technique becomes important - by encapsulating those properties
|
||||
that need to be considered on a type by type basis inside a
|
||||
traits class, we can minimise the amount of code that has to
|
||||
differ from one type to another, and maximise the amount of
|
||||
generic code.</p>
|
||||
|
||||
<p>Consider an example: when working with character strings, one
|
||||
common operation is to determine the length of a null terminated
|
||||
string. Clearly it's possible to write generic code that can do
|
||||
this, but it turns out that there are much more efficient methods
|
||||
available: for example, the C library functions <font size="2"
|
||||
face="Courier New">strlen</font> and <font size="2"
|
||||
face="Courier New">wcslen</font> are usually written in assembler,
|
||||
and with suitable hardware support can be considerably faster
|
||||
than a generic version written in C++. The authors of the C++
|
||||
standard library realised this, and abstracted the properties of <font
|
||||
size="2" face="Courier New">char</font> and <font size="2"
|
||||
face="Courier New">wchar_t</font> into the class <font size="2"
|
||||
face="Courier New">char_traits</font>. Generic code that works
|
||||
with character strings can simply use <font size="2"
|
||||
face="Courier New">char_traits<>::length</font> to
|
||||
determine the length of a null terminated string, safe in the
|
||||
knowledge that specialisations of <font size="2"
|
||||
face="Courier New">char_traits</font> will use the most
|
||||
appropriate method available to them.</p>
|
||||
|
||||
<h4>Type traits</h4>
|
||||
|
||||
<p>Class <font size="2" face="Courier New">char_traits</font> is
|
||||
a classic example of a collection of type specific properties
|
||||
wrapped up in a single class - what Nathan Myers termed a <i>baggage
|
||||
class</i>[1]. In the Boost type-traits library, we[2] have
|
||||
written a set of very specific traits classes, each of which
|
||||
encapsulate a single trait from the C++ type system; for example,
|
||||
is a type a pointer or a reference type? Or does a type have a
|
||||
trivial constructor, or a const-qualifier? The type-traits
|
||||
classes share a unified design: each class has a single member <i>value</i>,
|
||||
a compile-time constant that is true if the type has the
|
||||
specified property, and false otherwise. As we will show, these
|
||||
classes can be used in generic programming to determine the
|
||||
properties of a given type and introduce optimisations that are
|
||||
appropriate for that case.</p>
|
||||
|
||||
<p>The type-traits library also contains a set of classes that
|
||||
perform a specific transformation on a type; for example, they
|
||||
can remove a top-level const or volatile qualifier from a type.
|
||||
Each class that performs a transformation defines a single
|
||||
typedef-member <i>type</i> that is the result of the
|
||||
transformation. All of the type-traits classes are defined inside
|
||||
namespace <font size="2" face="Courier New">boost</font>; for
|
||||
brevity, namespace-qualification is omitted in most of the code
|
||||
samples given.</p>
|
||||
|
||||
<h4>Implementation</h4>
|
||||
|
||||
<p>There are far too many separate classes contained in the type-traits
|
||||
library to give a full implementation here - see the source code
|
||||
in the Boost library for the full details - however, most of the
|
||||
implementation is fairly repetitive anyway, so here we will just
|
||||
give you a flavour for how some of the classes are implemented.
|
||||
Beginning with possibly the simplest class in the library, is_void<T>
|
||||
has a member <i>value</i> that is true only if T is void.</p>
|
||||
|
||||
<pre>template <typename T>
|
||||
struct is_void
|
||||
{ static const bool value = false; };
|
||||
|
||||
template <>
|
||||
struct is_void<void>
|
||||
{ static const bool value = true; };</pre>
|
||||
|
||||
<p>Here we define a primary version of the template class <font
|
||||
size="2" face="Courier New">is_void</font>, and provide a full-specialisation
|
||||
when T is void. While full specialisation of a template class is
|
||||
an important technique, sometimes we need a solution that is
|
||||
halfway between a fully generic solution, and a full
|
||||
specialisation. This is exactly the situation for which the
|
||||
standards committee defined partial template-class specialisation.
|
||||
As an example, consider the class boost::is_pointer<T>:
|
||||
here we needed a primary version that handles all the cases where
|
||||
T is not a pointer, and a partial specialisation to handle all
|
||||
the cases where T is a pointer:</p>
|
||||
|
||||
<pre>template <typename T>
|
||||
struct is_pointer
|
||||
{ static const bool value = false; };
|
||||
|
||||
template <typename T>
|
||||
struct is_pointer<T*>
|
||||
{ static const bool value = true; };</pre>
|
||||
|
||||
<p>The syntax for partial specialisation is somewhat arcane and
|
||||
could easily occupy an article in its own right; like full
|
||||
specialisation, in order to write a partial specialisation for a
|
||||
class, you must first declare the primary template. The partial
|
||||
specialisation contains an extra <…> after the class
|
||||
name that contains the partial specialisation parameters; these
|
||||
define the types that will bind to that partial specialisation
|
||||
rather than the default template. The rules for what can appear
|
||||
in a partial specialisation are somewhat convoluted, but as a
|
||||
rule of thumb if you can legally write two function overloads of
|
||||
the form:</p>
|
||||
|
||||
<pre>void foo(T);
|
||||
void foo(U);</pre>
|
||||
|
||||
<p>Then you can also write a partial specialisation of the form:</p>
|
||||
|
||||
<pre>template <typename T>
|
||||
class c{ /*details*/ };
|
||||
|
||||
template <typename T>
|
||||
|
||||
class c<U>{ /*details*/ };</pre>
|
||||
|
||||
<p>This rule is by no means foolproof, but it is reasonably
|
||||
simple to remember and close enough to the actual rule to be
|
||||
useful for everyday use.</p>
|
||||
|
||||
<p>As a more complex example of partial specialisation consider
|
||||
the class remove_bounds<T>. This class defines a single
|
||||
typedef-member <i>type</i> that is the same type as T but with
|
||||
any top-level array bounds removed; this is an example of a
|
||||
traits class that performs a transformation on a type:</p>
|
||||
|
||||
<pre>template <typename T>
|
||||
struct remove_bounds
|
||||
{ typedef T type; };
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct remove_bounds<T[N]>
|
||||
{ typedef T type; };</pre>
|
||||
|
||||
<p>The aim of remove_bounds is this: imagine a generic algorithm
|
||||
that is passed an array type as a template parameter, <font
|
||||
size="2" face="Courier New">remove_bounds</font> provides a means
|
||||
of determining the underlying type of the array. For example <code>remove_bounds<int[4][5]>::type</code>
|
||||
would evaluate to the type <code>int[5]</code>. This example also
|
||||
shows that the number of template parameters in a partial
|
||||
specialisation does not have to match the number in the default
|
||||
template. However, the number of parameters that appear after the
|
||||
class name do have to match the number and type of the parameters
|
||||
in the default template.</p>
|
||||
|
||||
<h4>Optimised copy</h4>
|
||||
|
||||
<p>As an example of how the type traits classes can be used,
|
||||
consider the standard library algorithm copy:</p>
|
||||
|
||||
<pre>template<typename Iter1, typename Iter2>
|
||||
Iter2 copy(Iter1 first, Iter1 last, Iter2 out);</pre>
|
||||
|
||||
<p>Obviously, there's no problem writing a generic version of
|
||||
copy that works for all iterator types Iter1 and Iter2; however,
|
||||
there are some circumstances when the copy operation can best be
|
||||
performed by a call to <font size="2" face="Courier New">memcpy</font>.
|
||||
In order to implement copy in terms of <font size="2"
|
||||
face="Courier New">memcpy</font> all of the following conditions
|
||||
need to be met:</p>
|
||||
|
||||
<ul>
|
||||
<li>Both of the iterator types Iter1 and Iter2 must be
|
||||
pointers.</li>
|
||||
<li>Both Iter1 and Iter2 must point to the same type -
|
||||
excluding <font size="2" face="Courier New">const</font>
|
||||
and <font size="2" face="Courier New">volatile</font>-qualifiers.</li>
|
||||
<li>The type pointed to by Iter1 must have a trivial
|
||||
assignment operator.</li>
|
||||
</ul>
|
||||
|
||||
<p>By trivial assignment operator we mean that the type is either
|
||||
a scalar type[3] or:</p>
|
||||
|
||||
<ul>
|
||||
<li>The type has no user defined assignment operator.</li>
|
||||
<li>The type does not have any data members that are
|
||||
references.</li>
|
||||
<li>All base classes, and all data member objects must have
|
||||
trivial assignment operators.</li>
|
||||
</ul>
|
||||
|
||||
<p>If all these conditions are met then a type can be copied
|
||||
using <font size="2" face="Courier New">memcpy</font> rather than
|
||||
using a compiler generated assignment operator. The type-traits
|
||||
library provides a class <i>has_trivial_assign</i>, such that <code>has_trivial_assign<T>::value</code>
|
||||
is true only if T has a trivial assignment operator. This class
|
||||
"just works" for scalar types, but has to be explicitly
|
||||
specialised for class/struct types that also happen to have a
|
||||
trivial assignment operator. In other words if <i>has_trivial_assign</i>
|
||||
gives the wrong answer, it will give the "safe" wrong
|
||||
answer - that trivial assignment is not allowable.</p>
|
||||
|
||||
<p>The code for an optimised version of copy that uses <font
|
||||
size="2" face="Courier New">memcpy</font> where appropriate is
|
||||
given in listing 1. The code begins by defining a template class <i>copier</i>,
|
||||
that takes a single Boolean template parameter, and has a static
|
||||
template member function <font size="2" face="Courier New">do_copy</font>
|
||||
which performs the generic version of <font size="2">copy</font>
|
||||
(in other words the "slow but safe version"). Following
|
||||
that there is a specialisation for <i>copier<true></i>:
|
||||
again this defines a static template member function <font
|
||||
size="2" face="Courier New">do_copy</font>, but this version uses
|
||||
memcpy to perform an "optimised" copy.</p>
|
||||
|
||||
<p>In order to complete the implementation, what we need now is a
|
||||
version of copy, that calls <code>copier<true>::do_copy</code>
|
||||
if it is safe to use <font size="2" face="Courier New">memcpy</font>,
|
||||
and otherwise calls <code>copier<false>::do_copy</code> to
|
||||
do a "generic" copy. This is what the version in
|
||||
listing 1 does. To understand how the code works look at the code
|
||||
for <font size="2" face="Courier New">copy</font> and consider
|
||||
first the two typedefs <i>v1_t</i> and <i>v2_t</i>. These use <code>std::iterator_traits<Iter1>::value_type</code>
|
||||
to determine what type the two iterators point to, and then feed
|
||||
the result into another type-traits class <i>remove_cv</i> that
|
||||
removes the top-level const-volatile-qualifiers: this will allow
|
||||
copy to compare the two types without regard to const- or
|
||||
volatile-qualifiers. Next, <font size="2" face="Courier New">copy</font>
|
||||
declares an enumerated value <i>can_opt</i> that will become the
|
||||
template parameter to copier - declaring this here as a constant
|
||||
is really just a convenience - the value could be passed directly
|
||||
to class <font size="2" face="Courier New">copier</font>. The
|
||||
value of <i>can_opt</i> is computed by verifying that all of the
|
||||
following are true:</p>
|
||||
|
||||
<ul>
|
||||
<li>first that the two iterators point to the same type by
|
||||
using a type-traits class <i>is_same</i>.</li>
|
||||
<li>Then that both iterators are real pointers - using the
|
||||
class <i>is_pointer</i> described above.</li>
|
||||
<li>Finally that the pointed-to types have a trivial
|
||||
assignment operator using <i>has_trivial_assign</i>.</li>
|
||||
</ul>
|
||||
|
||||
<p>Finally we can use the value of <i>can_opt</i> as the template
|
||||
argument to copier - this version of copy will now adapt to
|
||||
whatever parameters are passed to it, if its possible to use <font
|
||||
size="2" face="Courier New">memcpy</font>, then it will do so,
|
||||
otherwise it will use a generic copy.</p>
|
||||
|
||||
<h4>Was it worth it?</h4>
|
||||
|
||||
<p>It has often been repeated in these columns that "premature
|
||||
optimisation is the root of all evil" [4]. So the question
|
||||
must be asked: was our optimisation premature? To put this in
|
||||
perspective the timings for our version of copy compared a
|
||||
conventional generic copy[5] are shown in table 1.</p>
|
||||
|
||||
<p>Clearly the optimisation makes a difference in this case; but,
|
||||
to be fair, the timings are loaded to exclude cache miss effects
|
||||
- without this accurate comparison between algorithms becomes
|
||||
difficult. However, perhaps we can add a couple of caveats to the
|
||||
premature optimisation rule:</p>
|
||||
|
||||
<ul>
|
||||
<li>If you use the right algorithm for the job in the first
|
||||
place then optimisation will not be required; in some
|
||||
cases, <font size="2" face="Courier New">memcpy</font> is
|
||||
the right algorithm.</li>
|
||||
<li>If a component is going to be reused in many places by
|
||||
many people then optimisations may well be worthwhile
|
||||
where they would not be so for a single case - in other
|
||||
words, the likelihood that the optimisation will be
|
||||
absolutely necessary somewhere, sometime is that much
|
||||
higher. Just as importantly the perceived value of the
|
||||
stock implementation will be higher: there is no point
|
||||
standardising an algorithm if users reject it on the
|
||||
grounds that there are better, more heavily optimised
|
||||
versions available.</li>
|
||||
</ul>
|
||||
|
||||
<h4>Table 1: Time taken to copy 1000 elements using copy<const
|
||||
T*, T*> (times in micro-seconds)</h4>
|
||||
|
||||
<table border="1" cellpadding="7" cellspacing="1" width="529">
|
||||
<tr>
|
||||
<td valign="top" width="33%"><p align="center">Version</p>
|
||||
</td>
|
||||
<td valign="top" width="33%"><p align="center">T</p>
|
||||
</td>
|
||||
<td valign="top" width="33%"><p align="center">Time</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="33%">"Optimised" copy</td>
|
||||
<td valign="top" width="33%">char</td>
|
||||
<td valign="top" width="33%">0.99</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="33%">Conventional copy</td>
|
||||
<td valign="top" width="33%">char</td>
|
||||
<td valign="top" width="33%">8.07</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="33%">"Optimised" copy</td>
|
||||
<td valign="top" width="33%">int</td>
|
||||
<td valign="top" width="33%">2.52</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="33%">Conventional copy</td>
|
||||
<td valign="top" width="33%">int</td>
|
||||
<td valign="top" width="33%">8.02</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<h4>Pair of References</h4>
|
||||
|
||||
<p>The optimised copy example shows how type traits may be used
|
||||
to perform optimisation decisions at compile-time. Another
|
||||
important usage of type traits is to allow code to compile that
|
||||
otherwise would not do so unless excessive partial specialization
|
||||
is used. This is possible by delegating partial specialization to
|
||||
the type traits classes. Our example for this form of usage is a
|
||||
pair that can hold references [6].</p>
|
||||
|
||||
<p>First, let us examine the definition of "std::pair",
|
||||
omitting the comparision operators, default constructor, and
|
||||
template copy constructor for simplicity:</p>
|
||||
|
||||
<pre>template <typename T1, typename T2>
|
||||
struct pair
|
||||
{
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
|
||||
T1 first;
|
||||
T2 second;
|
||||
|
||||
pair(const T1 & nfirst, const T2 & nsecond)
|
||||
:first(nfirst), second(nsecond) { }
|
||||
};</pre>
|
||||
|
||||
<p>Now, this "pair" cannot hold references as it
|
||||
currently stands, because the constructor would require taking a
|
||||
reference to a reference, which is currently illegal [7]. Let us
|
||||
consider what the constructor's parameters would have to be in
|
||||
order to allow "pair" to hold non-reference types,
|
||||
references, and constant references:</p>
|
||||
|
||||
<table border="1" cellpadding="7" cellspacing="1" width="638">
|
||||
<tr>
|
||||
<td valign="top" width="50%">Type of "T1"</td>
|
||||
<td valign="top" width="50%">Type of parameter to
|
||||
initializing constructor</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="50%"><pre>T</pre>
|
||||
</td>
|
||||
<td valign="top" width="50%"><pre>const T &</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="50%"><pre>T &</pre>
|
||||
</td>
|
||||
<td valign="top" width="50%"><pre>T &</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="50%"><pre>const T &</pre>
|
||||
</td>
|
||||
<td valign="top" width="50%"><pre>const T &</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>A little familiarity with the type traits classes allows us to
|
||||
construct a single mapping that allows us to determine the type
|
||||
of parameter from the type of the contained class. The type
|
||||
traits classes provide a transformation "add_reference",
|
||||
which adds a reference to its type, unless it is already a
|
||||
reference.</p>
|
||||
|
||||
<table border="1" cellpadding="7" cellspacing="1" width="580">
|
||||
<tr>
|
||||
<td valign="top" width="21%">Type of "T1"</td>
|
||||
<td valign="top" width="27%">Type of "const T1"</td>
|
||||
<td valign="top" width="53%">Type of "add_reference<const
|
||||
T1>::type"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="21%"><pre>T</pre>
|
||||
</td>
|
||||
<td valign="top" width="27%"><pre>const T</pre>
|
||||
</td>
|
||||
<td valign="top" width="53%"><pre>const T &</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="21%"><pre>T &</pre>
|
||||
</td>
|
||||
<td valign="top" width="27%"><pre>T & [8]</pre>
|
||||
</td>
|
||||
<td valign="top" width="53%"><pre>T &</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" width="21%"><pre>const T &</pre>
|
||||
</td>
|
||||
<td valign="top" width="27%"><pre>const T &</pre>
|
||||
</td>
|
||||
<td valign="top" width="53%"><pre>const T &</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>This allows us to build a primary template definition for
|
||||
"pair" that can contain non-reference types, reference
|
||||
types, and constant reference types:</p>
|
||||
|
||||
<pre>template <typename T1, typename T2>
|
||||
struct pair
|
||||
{
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
|
||||
T1 first;
|
||||
T2 second;
|
||||
|
||||
pair(boost::add_reference<const T1>::type nfirst,
|
||||
boost::add_reference<const T2>::type nsecond)
|
||||
:first(nfirst), second(nsecond) { }
|
||||
};</pre>
|
||||
|
||||
<p>Add back in the standard comparision operators, default
|
||||
constructor, and template copy constructor (which are all the
|
||||
same), and you have a std::pair that can hold reference types!</p>
|
||||
|
||||
<p>This same extension <i>could</i> have been done using partial
|
||||
template specialization of "pair", but to specialize
|
||||
"pair" in this way would require three partial
|
||||
specializations, plus the primary template. Type traits allows us
|
||||
to define a single primary template that adjusts itself auto-magically
|
||||
to any of these partial specializations, instead of a brute-force
|
||||
partial specialization approach. Using type traits in this
|
||||
fashion allows programmers to delegate partial specialization to
|
||||
the type traits classes, resulting in code that is easier to
|
||||
maintain and easier to understand.</p>
|
||||
|
||||
<h4>Conclusion</h4>
|
||||
|
||||
<p>We hope that in this article we have been able to give you
|
||||
some idea of what type-traits are all about. A more complete
|
||||
listing of the available classes are in the boost documentation,
|
||||
along with further examples using type traits. Templates have
|
||||
enabled C++ uses to take the advantage of the code reuse that
|
||||
generic programming brings; hopefully this article has shown that
|
||||
generic programming does not have to sink to the lowest common
|
||||
denominator, and that templates can be optimal as well as generic.</p>
|
||||
|
||||
<h4>Acknowledgements</h4>
|
||||
|
||||
<p>The authors would like to thank Beman Dawes and Howard Hinnant
|
||||
for their helpful comments when preparing this article.</p>
|
||||
|
||||
<h4>References</h4>
|
||||
|
||||
<ol>
|
||||
<li>Nathan C. Myers, C++ Report, June 1995.</li>
|
||||
<li>The type traits library is based upon contributions by
|
||||
Steve Cleary, Beman Dawes, Howard Hinnant and John
|
||||
Maddock: it can be found at www.boost.org.</li>
|
||||
<li>A scalar type is an arithmetic type (i.e. a built-in
|
||||
integer or floating point type), an enumeration type, a
|
||||
pointer, a pointer to member, or a const- or volatile-qualified
|
||||
version of one of these types.</li>
|
||||
<li>This quote is from Donald Knuth, ACM Computing Surveys,
|
||||
December 1974, pg 268.</li>
|
||||
<li>The test code is available as part of the boost utility
|
||||
library (see algo_opt_examples.cpp), the code was
|
||||
compiled with gcc 2.95 with all optimisations turned on,
|
||||
tests were conducted on a 400MHz Pentium II machine
|
||||
running Microsoft Windows 98.</li>
|
||||
<li>John Maddock and Howard Hinnant have submitted a "compressed_pair"
|
||||
library to Boost, which uses a technique similar to the
|
||||
one described here to hold references. Their pair also
|
||||
uses type traits to determine if any of the types are
|
||||
empty, and will derive instead of contain to conserve
|
||||
space -- hence the name "compressed".</li>
|
||||
<li>This is actually an issue with the C++ Core Language
|
||||
Working Group (issue #106), submitted by Bjarne
|
||||
Stroustrup. The tentative resolution is to allow a "reference
|
||||
to a reference to T" to mean the same thing as a
|
||||
"reference to T", but only in template
|
||||
instantiation, in a method similar to multiple cv-qualifiers.</li>
|
||||
<li>For those of you who are wondering why this shouldn't be
|
||||
const-qualified, remember that references are always
|
||||
implicitly constant (for example, you can't re-assign a
|
||||
reference). Remember also that "const T &"
|
||||
is something completely different. For this reason, cv-qualifiers
|
||||
on template type arguments that are references are
|
||||
ignored.</li>
|
||||
</ol>
|
||||
|
||||
<h2>Listing 1</h2>
|
||||
|
||||
<pre>namespace detail{
|
||||
|
||||
template <bool b>
|
||||
struct copier
|
||||
{
|
||||
template<typename I1, typename I2>
|
||||
static I2 do_copy(I1 first,
|
||||
I1 last, I2 out);
|
||||
};
|
||||
|
||||
template <bool b>
|
||||
template<typename I1, typename I2>
|
||||
I2 copier<b>::do_copy(I1 first,
|
||||
I1 last,
|
||||
I2 out)
|
||||
{
|
||||
while(first != last)
|
||||
{
|
||||
*out = *first;
|
||||
++out;
|
||||
++first;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct copier<true>
|
||||
{
|
||||
template<typename I1, typename I2>
|
||||
static I2* do_copy(I1* first, I1* last, I2* out)
|
||||
{
|
||||
memcpy(out, first, (last-first)*sizeof(I2));
|
||||
return out+(last-first);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename I1, typename I2>
|
||||
inline I2 copy(I1 first, I1 last, I2 out)
|
||||
{
|
||||
typedef typename
|
||||
boost::remove_cv<
|
||||
typename std::iterator_traits<I1>
|
||||
::value_type>::type v1_t;
|
||||
|
||||
typedef typename
|
||||
boost::remove_cv<
|
||||
typename std::iterator_traits<I2>
|
||||
::value_type>::type v2_t;
|
||||
|
||||
enum{ can_opt =
|
||||
boost::is_same<v1_t, v2_t>::value
|
||||
&& boost::is_pointer<I1>::value
|
||||
&& boost::is_pointer<I2>::value
|
||||
&& boost::
|
||||
has_trivial_assign<v1_t>::value
|
||||
};
|
||||
|
||||
return detail::copier<can_opt>::
|
||||
do_copy(first, last, out);
|
||||
}</pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<p><EFBFBD> Copyright John Maddock and Steve Cleary, 2000</p>
|
||||
</body>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=../../doc/html/boost_typetraits/background.html">
|
||||
</head>
|
||||
<body>
|
||||
Automatic redirection failed, please go to
|
||||
<a href="../../doc/html/boost_typetraits/background.html">../../doc/html/boost_typetraits/background.html</a>
|
||||
or view the online version at
|
||||
<a href="http://www.boost.org/regression-logs/cs-win32_metacomm/doc/html/boost_typetraits/background.html">http://www.boost.org/regression-logs/cs-win32_metacomm/doc/html/boost_typetraits/background.html</a>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
1241
index.html
1241
index.html
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user