mirror of
https://github.com/boostorg/utility.git
synced 2025-10-19 03:35:19 +02:00
Compare commits
25 Commits
svn-branch
...
svn-branch
Author | SHA1 | Date | |
---|---|---|---|
|
09b13c55b2 | ||
|
aa26bc2137 | ||
|
f6533b3826 | ||
|
e5c81d0702 | ||
|
6caf7d4d5a | ||
|
98e87c8afb | ||
|
d9e0f80d50 | ||
|
6396fdb5ff | ||
|
2470b53373 | ||
|
16334e92ca | ||
|
c22d98a8ec | ||
|
28617afbb9 | ||
|
0c3bc42bec | ||
|
e3d9745df1 | ||
|
b8471c1015 | ||
|
045b09c9ef | ||
|
4ac07b97d3 | ||
|
34c847c17f | ||
|
f694e557e1 | ||
|
6a0c3e92a0 | ||
|
cba48df8e3 | ||
|
a0e8d1bf36 | ||
|
912dedaca7 | ||
|
7dd90c3919 | ||
|
7c3a25a377 |
@@ -1,489 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<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 a draft of an article that will appear in a future
|
||||
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 <<EFBFBD>> 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>
|
||||
|
||||
</html>
|
53
counting_iterator_example.cpp
Normal file
53
counting_iterator_example.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <boost/counting_iterator.hpp>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
// Example of using counting_iterator_generator
|
||||
std::cout << "counting from 0 to 4:" << std::endl;
|
||||
boost::counting_iterator_generator<int>::type first(0), last(4);
|
||||
std::copy(first, last, std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
// Example of using make_counting_iterator()
|
||||
std::cout << "counting from -5 to 4:" << std::endl;
|
||||
std::copy(boost::make_counting_iterator(-5),
|
||||
boost::make_counting_iterator(5),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
// Example of using counting iterator to create an array of pointers.
|
||||
const int N = 7;
|
||||
std::vector<int> numbers;
|
||||
// Fill "numbers" array with [0,N)
|
||||
std::copy(boost::make_counting_iterator(0), boost::make_counting_iterator(N),
|
||||
std::back_inserter(numbers));
|
||||
|
||||
std::vector<std::vector<int>::iterator> pointers;
|
||||
|
||||
// Use counting iterator to fill in the array of pointers.
|
||||
std::copy(boost::make_counting_iterator(numbers.begin()),
|
||||
boost::make_counting_iterator(numbers.end()),
|
||||
std::back_inserter(pointers));
|
||||
|
||||
// Use indirect iterator to print out numbers by accessing
|
||||
// them through the array of pointers.
|
||||
std::cout << "indirectly printing out the numbers from 0 to "
|
||||
<< N << std::endl;
|
||||
std::copy(boost::make_indirect_iterator(pointers.begin()),
|
||||
boost::make_indirect_iterator(pointers.end()),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
428
include/boost/detail/compressed_pair.hpp
Normal file
428
include/boost/detail/compressed_pair.hpp
Normal file
@@ -0,0 +1,428 @@
|
||||
// (C) Copyright Steve Cleary, Beman Dawes, Howard Hinnant & John Maddock 2000.
|
||||
// Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
// compressed_pair: pair that "compresses" empty members
|
||||
// (see libs/utility/compressed_pair.htm)
|
||||
//
|
||||
// JM changes 25 Jan 2000:
|
||||
// Removed default arguments from compressed_pair_switch to get
|
||||
// C++ Builder 4 to accept them
|
||||
// rewriten swap to get gcc and C++ builder to compile.
|
||||
// added partial specialisations for case T1 == T2 to avoid duplicate constructor defs.
|
||||
|
||||
#ifndef BOOST_DETAIL_COMPRESSED_PAIR_HPP
|
||||
#define BOOST_DETAIL_COMPRESSED_PAIR_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#ifndef BOOST_OBJECT_TYPE_TRAITS_HPP
|
||||
#include <boost/type_traits/object_traits.hpp>
|
||||
#endif
|
||||
#ifndef BOOST_SAME_TRAITS_HPP
|
||||
#include <boost/type_traits/same_traits.hpp>
|
||||
#endif
|
||||
#ifndef BOOST_CALL_TRAITS_HPP
|
||||
#include <boost/call_traits.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
// compressed_pair
|
||||
|
||||
namespace details
|
||||
{
|
||||
// JM altered 26 Jan 2000:
|
||||
template <class T1, class T2, bool IsSame, bool FirstEmpty, bool SecondEmpty>
|
||||
struct compressed_pair_switch;
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_switch<T1, T2, false, false, false>
|
||||
{static const int value = 0;};
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_switch<T1, T2, false, true, true>
|
||||
{static const int value = 3;};
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_switch<T1, T2, false, true, false>
|
||||
{static const int value = 1;};
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_switch<T1, T2, false, false, true>
|
||||
{static const int value = 2;};
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_switch<T1, T2, true, true, true>
|
||||
{static const int value = 4;};
|
||||
|
||||
template <class T1, class T2>
|
||||
struct compressed_pair_switch<T1, T2, true, false, false>
|
||||
{static const int value = 5;};
|
||||
|
||||
template <class T1, class T2, int Version> class compressed_pair_imp;
|
||||
|
||||
#ifdef __GNUC__
|
||||
// workaround for GCC (JM):
|
||||
using std::swap;
|
||||
#endif
|
||||
//
|
||||
// can't call unqualified swap from within classname::swap
|
||||
// as Koenig lookup rules will find only the classname::swap
|
||||
// member function not the global declaration, so use cp_swap
|
||||
// as a forwarding function (JM):
|
||||
template <typename T>
|
||||
inline void cp_swap(T& t1, T& t2)
|
||||
{
|
||||
#ifndef __GNUC__
|
||||
using std::swap;
|
||||
#endif
|
||||
swap(t1, t2);
|
||||
}
|
||||
|
||||
// 0 derive from neither
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 0>
|
||||
{
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair_imp() {}
|
||||
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: first_(x), second_(y) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
: first_(x) {}
|
||||
|
||||
explicit compressed_pair_imp(second_param_type y)
|
||||
: second_(y) {}
|
||||
|
||||
first_reference first() {return first_;}
|
||||
first_const_reference first() const {return first_;}
|
||||
|
||||
second_reference second() {return second_;}
|
||||
second_const_reference second() const {return second_;}
|
||||
|
||||
void swap(compressed_pair_imp& y)
|
||||
{
|
||||
cp_swap(first_, y.first_);
|
||||
cp_swap(second_, y.second_);
|
||||
}
|
||||
private:
|
||||
first_type first_;
|
||||
second_type second_;
|
||||
};
|
||||
|
||||
// 1 derive from T1
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 1>
|
||||
: private T1
|
||||
{
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair_imp() {}
|
||||
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: first_type(x), second_(y) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
: first_type(x) {}
|
||||
|
||||
explicit compressed_pair_imp(second_param_type y)
|
||||
: second_(y) {}
|
||||
|
||||
first_reference first() {return *this;}
|
||||
first_const_reference first() const {return *this;}
|
||||
|
||||
second_reference second() {return second_;}
|
||||
second_const_reference second() const {return second_;}
|
||||
|
||||
void swap(compressed_pair_imp& y)
|
||||
{
|
||||
// no need to swap empty base class:
|
||||
cp_swap(second_, y.second_);
|
||||
}
|
||||
private:
|
||||
second_type second_;
|
||||
};
|
||||
|
||||
// 2 derive from T2
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 2>
|
||||
: private T2
|
||||
{
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair_imp() {}
|
||||
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: second_type(y), first_(x) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
: first_(x) {}
|
||||
|
||||
explicit compressed_pair_imp(second_param_type y)
|
||||
: second_type(y) {}
|
||||
|
||||
first_reference first() {return first_;}
|
||||
first_const_reference first() const {return first_;}
|
||||
|
||||
second_reference second() {return *this;}
|
||||
second_const_reference second() const {return *this;}
|
||||
|
||||
void swap(compressed_pair_imp& y)
|
||||
{
|
||||
// no need to swap empty base class:
|
||||
cp_swap(first_, y.first_);
|
||||
}
|
||||
|
||||
private:
|
||||
first_type first_;
|
||||
};
|
||||
|
||||
// 3 derive from T1 and T2
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 3>
|
||||
: private T1,
|
||||
private T2
|
||||
{
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair_imp() {}
|
||||
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: first_type(x), second_type(y) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
: first_type(x) {}
|
||||
|
||||
explicit compressed_pair_imp(second_param_type y)
|
||||
: second_type(y) {}
|
||||
|
||||
first_reference first() {return *this;}
|
||||
first_const_reference first() const {return *this;}
|
||||
|
||||
second_reference second() {return *this;}
|
||||
second_const_reference second() const {return *this;}
|
||||
//
|
||||
// no need to swap empty bases:
|
||||
void swap(compressed_pair_imp&) {}
|
||||
};
|
||||
|
||||
// JM
|
||||
// 4 T1 == T2, T1 and T2 both empty
|
||||
// Note does not actually store an instance of T2 at all -
|
||||
// but reuses T1 base class for both first() and second().
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 4>
|
||||
: private T1
|
||||
{
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair_imp() {}
|
||||
|
||||
compressed_pair_imp(first_param_type x, second_param_type)
|
||||
: first_type(x) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
: first_type(x) {}
|
||||
|
||||
first_reference first() {return *this;}
|
||||
first_const_reference first() const {return *this;}
|
||||
|
||||
second_reference second() {return *this;}
|
||||
second_const_reference second() const {return *this;}
|
||||
|
||||
void swap(compressed_pair_imp&) {}
|
||||
private:
|
||||
};
|
||||
|
||||
// 5 T1 == T2 and are not empty: //JM
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair_imp<T1, T2, 5>
|
||||
{
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair_imp() {}
|
||||
|
||||
compressed_pair_imp(first_param_type x, second_param_type y)
|
||||
: first_(x), second_(y) {}
|
||||
|
||||
explicit compressed_pair_imp(first_param_type x)
|
||||
: first_(x), second_(x) {}
|
||||
|
||||
first_reference first() {return first_;}
|
||||
first_const_reference first() const {return first_;}
|
||||
|
||||
second_reference second() {return second_;}
|
||||
second_const_reference second() const {return second_;}
|
||||
|
||||
void swap(compressed_pair_imp<T1, T2, 5>& y)
|
||||
{
|
||||
cp_swap(first_, y.first_);
|
||||
cp_swap(second_, y.second_);
|
||||
}
|
||||
private:
|
||||
first_type first_;
|
||||
second_type second_;
|
||||
};
|
||||
|
||||
} // details
|
||||
|
||||
template <class T1, class T2>
|
||||
class compressed_pair
|
||||
: private ::boost::details::compressed_pair_imp<T1, T2,
|
||||
::boost::details::compressed_pair_switch<
|
||||
T1,
|
||||
T2,
|
||||
::boost::is_same<typename remove_cv<T1>::type, typename remove_cv<T2>::type>::value,
|
||||
::boost::is_empty<T1>::value,
|
||||
::boost::is_empty<T2>::value>::value>
|
||||
{
|
||||
private:
|
||||
typedef details::compressed_pair_imp<T1, T2,
|
||||
::boost::details::compressed_pair_switch<
|
||||
T1,
|
||||
T2,
|
||||
::boost::is_same<typename remove_cv<T1>::type, typename remove_cv<T2>::type>::value,
|
||||
::boost::is_empty<T1>::value,
|
||||
::boost::is_empty<T2>::value>::value> base;
|
||||
public:
|
||||
typedef T1 first_type;
|
||||
typedef T2 second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair() : base() {}
|
||||
compressed_pair(first_param_type x, second_param_type y) : base(x, y) {}
|
||||
explicit compressed_pair(first_param_type x) : base(x) {}
|
||||
explicit compressed_pair(second_param_type y) : base(y) {}
|
||||
|
||||
first_reference first() {return base::first();}
|
||||
first_const_reference first() const {return base::first();}
|
||||
|
||||
second_reference second() {return base::second();}
|
||||
second_const_reference second() const {return base::second();}
|
||||
|
||||
void swap(compressed_pair& y) { base::swap(y); }
|
||||
};
|
||||
|
||||
// JM
|
||||
// Partial specialisation for case where T1 == T2:
|
||||
//
|
||||
template <class T>
|
||||
class compressed_pair<T, T>
|
||||
: private details::compressed_pair_imp<T, T,
|
||||
::boost::details::compressed_pair_switch<
|
||||
T,
|
||||
T,
|
||||
::boost::is_same<typename remove_cv<T>::type, typename remove_cv<T>::type>::value,
|
||||
::boost::is_empty<T>::value,
|
||||
::boost::is_empty<T>::value>::value>
|
||||
{
|
||||
private:
|
||||
typedef details::compressed_pair_imp<T, T,
|
||||
::boost::details::compressed_pair_switch<
|
||||
T,
|
||||
T,
|
||||
::boost::is_same<typename remove_cv<T>::type, typename remove_cv<T>::type>::value,
|
||||
::boost::is_empty<T>::value,
|
||||
::boost::is_empty<T>::value>::value> base;
|
||||
public:
|
||||
typedef T first_type;
|
||||
typedef T second_type;
|
||||
typedef typename call_traits<first_type>::param_type first_param_type;
|
||||
typedef typename call_traits<second_type>::param_type second_param_type;
|
||||
typedef typename call_traits<first_type>::reference first_reference;
|
||||
typedef typename call_traits<second_type>::reference second_reference;
|
||||
typedef typename call_traits<first_type>::const_reference first_const_reference;
|
||||
typedef typename call_traits<second_type>::const_reference second_const_reference;
|
||||
|
||||
compressed_pair() : base() {}
|
||||
compressed_pair(first_param_type x, second_param_type y) : base(x, y) {}
|
||||
explicit compressed_pair(first_param_type x) : base(x) {}
|
||||
|
||||
first_reference first() {return base::first();}
|
||||
first_const_reference first() const {return base::first();}
|
||||
|
||||
second_reference second() {return base::second();}
|
||||
second_const_reference second() const {return base::second();}
|
||||
|
||||
void swap(compressed_pair& y) { base::swap(y); }
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
inline
|
||||
void
|
||||
swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
} // boost
|
||||
|
||||
#endif // BOOST_DETAIL_COMPRESSED_PAIR_HPP
|
||||
|
||||
|
||||
|
128
include/boost/detail/ob_call_traits.hpp
Normal file
128
include/boost/detail/ob_call_traits.hpp
Normal file
@@ -0,0 +1,128 @@
|
||||
// (C) Copyright Steve Cleary, Beman Dawes, Howard Hinnant & John Maddock 2000.
|
||||
// Permission to copy, use, modify, sell and
|
||||
// distribute this software is granted provided this copyright notice appears
|
||||
// in all copies. This software is provided "as is" without express or implied
|
||||
// warranty, and with no claim as to its suitability for any purpose.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
//
|
||||
// Crippled version for crippled compilers:
|
||||
// see libs/utility/call_traits.htm
|
||||
//
|
||||
|
||||
/* Release notes:
|
||||
01st October 2000:
|
||||
Fixed call_traits on VC6, using "poor man's partial specialisation",
|
||||
using ideas taken from "Generative programming" by Krzysztof Czarnecki
|
||||
& Ulrich Eisenecker.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_OB_CALL_TRAITS_HPP
|
||||
#define BOOST_OB_CALL_TRAITS_HPP
|
||||
|
||||
#ifndef BOOST_CONFIG_HPP
|
||||
#include <boost/config.hpp>
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_ARITHMETIC_TYPE_TRAITS_HPP
|
||||
#include <boost/type_traits/arithmetic_traits.hpp>
|
||||
#endif
|
||||
#ifndef BOOST_COMPOSITE_TYPE_TRAITS_HPP
|
||||
#include <boost/type_traits/composite_traits.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
|
||||
#if defined(BOOST_MSVC6_MEMBER_TEMPLATES) || !defined(BOOST_NO_MEMBER_TEMPLATES)
|
||||
//
|
||||
// use member templates to emulate
|
||||
// partial specialisation:
|
||||
//
|
||||
namespace detail{
|
||||
|
||||
template <class T>
|
||||
struct standard_call_traits
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef const T& param_type;
|
||||
};
|
||||
template <class T>
|
||||
struct simple_call_traits
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef const T param_type;
|
||||
};
|
||||
template <class T>
|
||||
struct reference_call_traits
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef T reference;
|
||||
typedef T const_reference;
|
||||
typedef T param_type;
|
||||
};
|
||||
template <bool simple, bool reference>
|
||||
struct call_traits_chooser
|
||||
{
|
||||
template <class T>
|
||||
struct rebind
|
||||
{
|
||||
typedef standard_call_traits<T> type;
|
||||
};
|
||||
};
|
||||
template <>
|
||||
struct call_traits_chooser<true, false>
|
||||
{
|
||||
template <class T>
|
||||
struct rebind
|
||||
{
|
||||
typedef simple_call_traits<T> type;
|
||||
};
|
||||
};
|
||||
template <>
|
||||
struct call_traits_chooser<false, true>
|
||||
{
|
||||
template <class T>
|
||||
struct rebind
|
||||
{
|
||||
typedef reference_call_traits<T> type;
|
||||
};
|
||||
};
|
||||
} // namespace detail
|
||||
template <typename T>
|
||||
struct call_traits
|
||||
{
|
||||
private:
|
||||
typedef detail::call_traits_chooser<(is_pointer<T>::value || is_arithmetic<T>::value) && sizeof(T) <= sizeof(void*), is_reference<T>::value> chooser;
|
||||
typedef typename chooser::template rebind<T> bound_type;
|
||||
typedef typename bound_type::type call_traits_type;
|
||||
public:
|
||||
typedef typename call_traits_type::value_type value_type;
|
||||
typedef typename call_traits_type::reference reference;
|
||||
typedef typename call_traits_type::const_reference const_reference;
|
||||
typedef typename call_traits_type::param_type param_type;
|
||||
};
|
||||
|
||||
#else
|
||||
//
|
||||
// sorry call_traits is completely non-functional
|
||||
// blame your broken compiler:
|
||||
//
|
||||
|
||||
template <typename T>
|
||||
struct call_traits
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef const T& param_type;
|
||||
};
|
||||
|
||||
#endif // member templates
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOST_OB_CALL_TRAITS_HPP
|
210
iterator_traits_test.cpp
Normal file
210
iterator_traits_test.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
// (C) Copyright David Abrahams 2001. Permission to copy, use, modify,
|
||||
// sell and distribute this software is granted provided this
|
||||
// copyright notice appears in all copies. This software is provided
|
||||
// "as is" without express or implied warranty, and with no claim as
|
||||
// to its suitability for any purpose.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
// Revision History
|
||||
// 04 Mar 2001 Patches for Intel C++ (Dave Abrahams)
|
||||
// 19 Feb 2001 Take advantage of improved iterator_traits to do more tests
|
||||
// on MSVC. Reordered some #ifdefs for coherency.
|
||||
// (David Abrahams)
|
||||
// 13 Feb 2001 Test new VC6 workarounds (David Abrahams)
|
||||
// 11 Feb 2001 Final fixes for Borland (David Abrahams)
|
||||
// 11 Feb 2001 Some fixes for Borland get it closer on that compiler
|
||||
// (David Abrahams)
|
||||
// 07 Feb 2001 More comprehensive testing; factored out static tests for
|
||||
// better reuse (David Abrahams)
|
||||
// 21 Jan 2001 Quick fix to my_iterator, which wasn't returning a
|
||||
// reference type from operator* (David Abrahams)
|
||||
// 19 Jan 2001 Initial version with iterator operators (David Abrahams)
|
||||
|
||||
#include <boost/detail/iterator.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/operators.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
// An iterator for which we can get traits.
|
||||
struct my_iterator1
|
||||
: boost::forward_iterator_helper<my_iterator1, char, long, const char*, const char&>
|
||||
{
|
||||
my_iterator1(const char* p) : m_p(p) {}
|
||||
|
||||
bool operator==(const my_iterator1& rhs) const
|
||||
{ return this->m_p == rhs.m_p; }
|
||||
|
||||
my_iterator1& operator++() { ++this->m_p; return *this; }
|
||||
const char& operator*() { return *m_p; }
|
||||
private:
|
||||
const char* m_p;
|
||||
};
|
||||
|
||||
// Used to prove that we don't require std::iterator<> in the hierarchy under
|
||||
// MSVC6, and that we can compute all the traits for a standard-conforming UDT
|
||||
// iterator.
|
||||
struct my_iterator2
|
||||
: boost::equality_comparable<my_iterator2
|
||||
, boost::incrementable<my_iterator2
|
||||
, boost::dereferenceable<my_iterator2,const char*> > >
|
||||
{
|
||||
typedef char value_type;
|
||||
typedef long difference_type;
|
||||
typedef const char* pointer;
|
||||
typedef const char& reference;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
my_iterator2(const char* p) : m_p(p) {}
|
||||
|
||||
bool operator==(const my_iterator2& rhs) const
|
||||
{ return this->m_p == rhs.m_p; }
|
||||
|
||||
my_iterator2& operator++() { ++this->m_p; return *this; }
|
||||
const char& operator*() { return *m_p; }
|
||||
private:
|
||||
const char* m_p;
|
||||
};
|
||||
|
||||
// Used to prove that we're not overly confused by the existence of
|
||||
// std::iterator<> in the hierarchy under MSVC6 - we should find that
|
||||
// boost::detail::iterator_traits<my_iterator3>::difference_type is int.
|
||||
struct my_iterator3 : my_iterator1
|
||||
{
|
||||
typedef int difference_type;
|
||||
my_iterator3(const char* p) : my_iterator1(p) {}
|
||||
};
|
||||
|
||||
template <class Iterator,
|
||||
class value_type, class difference_type, class pointer, class reference, class category>
|
||||
struct non_portable_tests
|
||||
{
|
||||
// Unfortunately, the VC6 standard library doesn't supply these :(
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<
|
||||
typename boost::detail::iterator_traits<Iterator>::pointer,
|
||||
pointer
|
||||
>::value));
|
||||
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<
|
||||
typename boost::detail::iterator_traits<Iterator>::reference,
|
||||
reference
|
||||
>::value));
|
||||
};
|
||||
|
||||
template <class Iterator,
|
||||
class value_type, class difference_type, class pointer, class reference, class category>
|
||||
struct portable_tests
|
||||
{
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<
|
||||
typename boost::detail::iterator_traits<Iterator>::difference_type,
|
||||
difference_type
|
||||
>::value));
|
||||
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<
|
||||
typename boost::detail::iterator_traits<Iterator>::iterator_category,
|
||||
category
|
||||
>::value));
|
||||
};
|
||||
|
||||
// Test iterator_traits
|
||||
template <class Iterator,
|
||||
class value_type, class difference_type, class pointer, class reference, class category>
|
||||
struct input_iterator_test
|
||||
: portable_tests<Iterator,value_type,difference_type,pointer,reference,category>
|
||||
{
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<
|
||||
typename boost::detail::iterator_traits<Iterator>::value_type,
|
||||
value_type
|
||||
>::value));
|
||||
};
|
||||
|
||||
template <class Iterator,
|
||||
class value_type, class difference_type, class pointer, class reference, class category>
|
||||
struct non_pointer_test
|
||||
: input_iterator_test<Iterator,value_type,difference_type,pointer,reference,category>
|
||||
, non_portable_tests<Iterator,value_type,difference_type,pointer,reference,category>
|
||||
{
|
||||
};
|
||||
|
||||
template <class Iterator,
|
||||
class value_type, class difference_type, class pointer, class reference, class category>
|
||||
struct maybe_pointer_test
|
||||
: portable_tests<Iterator,value_type,difference_type,pointer,reference,category>
|
||||
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
, non_portable_tests<Iterator,value_type,difference_type,pointer,reference,category>
|
||||
#endif
|
||||
{
|
||||
};
|
||||
|
||||
input_iterator_test<std::istream_iterator<int>, int, std::ptrdiff_t, int*, int&, std::input_iterator_tag>
|
||||
istream_iterator_test;
|
||||
|
||||
//
|
||||
#if defined(__BORLANDC__) && !defined(__SGI_STL_PORT)
|
||||
typedef ::std::char_traits<char>::off_type distance;
|
||||
non_pointer_test<std::ostream_iterator<int>,int,
|
||||
distance,int*,int&,std::output_iterator_tag> ostream_iterator_test;
|
||||
#elif defined(BOOST_MSVC_STD_ITERATOR)
|
||||
non_pointer_test<std::ostream_iterator<int>,
|
||||
int, void, void, void, std::output_iterator_tag>
|
||||
ostream_iterator_test;
|
||||
#else
|
||||
non_pointer_test<std::ostream_iterator<int>,
|
||||
void, void, void, void, std::output_iterator_tag>
|
||||
ostream_iterator_test;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __KCC
|
||||
typedef long std_list_diff_type;
|
||||
#else
|
||||
typedef std::ptrdiff_t std_list_diff_type;
|
||||
#endif
|
||||
non_pointer_test<std::list<int>::iterator, int, std_list_diff_type, int*, int&, std::bidirectional_iterator_tag>
|
||||
list_iterator_test;
|
||||
|
||||
maybe_pointer_test<std::vector<int>::iterator, int, std::ptrdiff_t, int*, int&, std::random_access_iterator_tag>
|
||||
vector_iterator_test;
|
||||
|
||||
maybe_pointer_test<int*, int, std::ptrdiff_t, int*, int&, std::random_access_iterator_tag>
|
||||
int_pointer_test;
|
||||
|
||||
non_pointer_test<my_iterator1, char, long, const char*, const char&, std::forward_iterator_tag>
|
||||
my_iterator1_test;
|
||||
|
||||
non_pointer_test<my_iterator2, char, long, const char*, const char&, std::forward_iterator_tag>
|
||||
my_iterator2_test;
|
||||
|
||||
non_pointer_test<my_iterator3, char, int, const char*, const char&, std::forward_iterator_tag>
|
||||
my_iterator3_test;
|
||||
|
||||
int main()
|
||||
{
|
||||
char chars[100];
|
||||
int ints[100];
|
||||
|
||||
for (std::ptrdiff_t length = 3; length < 100; length += length / 3)
|
||||
{
|
||||
std::list<int> l(length);
|
||||
assert(boost::detail::distance(l.begin(), l.end()) == length);
|
||||
|
||||
std::vector<int> v(length);
|
||||
assert(boost::detail::distance(v.begin(), v.end()) == length);
|
||||
|
||||
assert(boost::detail::distance(&ints[0], ints + length) == length);
|
||||
assert(boost::detail::distance(my_iterator1(chars), my_iterator1(chars + length)) == length);
|
||||
assert(boost::detail::distance(my_iterator2(chars), my_iterator2(chars + length)) == length);
|
||||
assert(boost::detail::distance(my_iterator3(chars), my_iterator3(chars + length)) == length);
|
||||
}
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user