⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chap08.htm

📁 This is the second part of that lab manual to teach you how to make real-time programme and how to d
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<B>vector&lt;T&gt;</B>, along with an optional message. Since
<B>print(&#160;)</B> uses the STL <B>copy(&#160;)</B> algorithm to send objects
to <B>cout</B> via an <B>ostream_iterator</B>, the <B>ostream_iterator</B> must
know the type of object it is printing, and therefore the <B>print(&#160;)</B>
template must know this type also. However, you&#8217;ll see in
<B>main(&#160;)</B> that the compiler can deduce the type of <B>T</B> when you
hand it a <B>vector&lt;T&gt;</B>, so you don&#8217;t have to hand it the
template argument explicitly; you just say <B>print(x)</B> to print the
<B>vector&lt;T&gt; x</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The next two template functions automate
the process of testing the various function object templates. There are two
since the function objects are either unary or binary. In
<B>testUnary(&#160;)</B>, you pass a source and destination vector, and a unary
function object to apply to the source vector to produce the destination vector.
In <B>testBinary(&#160;)</B>, there are two source vectors which are fed to a
binary function to produce the destination vector. In both cases, the template
functions simply turn around and call the <B>transform(&#160;)</B> algorithm,
although the tests could certainly be more complex.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">For each test, you want to see a string
describing what the test is, followed by the results of the test. To automate
this, the preprocessor comes in handy; the <B>T(&#160;)</B> and <B>B(&#160;)</B>
macros each take the expression you want to execute. They call that expression,
then call <B>print(&#160;)</B>, passing it the result vector (they assume the
expression changes a vector named <B>r</B> and <B>br</B>, respectively), and to
produce the message the expression is &#8220;string-ized&#8221; using the
preprocessor. So that way you see the code of the expression that is executed
followed by the result vector.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The last little tool is a generator
object that creates random <B>bool</B> values. To do this, it gets a random
number from <B>rand(&#160;)</B> and tests to see if it&#8217;s greater than
<B>RAND_MAX/2</B>. If the random numbers are evenly distributed, this should
happen half the time.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In <B>main(&#160;)</B>, three
<B>vector&lt;int&gt;</B> are created: <B>x</B> and <B>y</B> for source values,
and <B>r</B> for results. To initialize <B>x</B> and <B>y</B> with random values
no greater than 50, a generator of type <B>URandGen</B> is used; this will be
defined shortly. Since there is one operation where elements of <B>x</B> are
divided by elements of <B>y</B>, we must ensure that there are no zero values of
<B>y</B>. This is accomplished using the <B>transform(&#160;)</B> algorithm,
taking the source values from <B>y</B> and putting the results back into
<B>y</B>. The function object for this is created with the
expression:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>bind2nd(plus&lt;<font color=#0000ff>int</font>&gt;(), 1)</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This uses the <B>plus</B> function object
that adds two objects together. It is thus a binary function which requires two
arguments; we only want to pass it one argument (the element from <B>y</B>) and
have the other argument be the value 1. A &#8220;binder&#8221; does the trick
(we will look at these next). The binder in this case says &#8220;make a new
function object which is the <B>plus</B> function object with the second
argument fixed at 1.&#8221; </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Another of the tests in the program
compares the elements in the two vectors for equality, so it is interesting to
guarantee that at least one pair of elements is equivalent; in this case element
zero is chosen.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Once the two vectors are printed,
<B>T(&#160;)</B> is used to test each of the function objects that produces a
numerical value, and then <B>B(&#160;)</B> is used to test each function object
that produces a Boolean result. The result is placed into a
<B>vector&lt;bool&gt;</B>, and when this vector is printed it produces a
&#8216;<B>1</B>&#8217; for a true value and a &#8216;<B>0</B>&#8217; for a false
value.</FONT><BR></P></DIV>
<A NAME="Heading251"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H4 ALIGN="LEFT">
Binders</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It&#8217;s common to want to take a
binary function object and to &#8220;bind&#8221; one of its arguments to a
constant value. After binding, you get a unary function object.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">For example, suppose you want to find
integers that are less than a particular value, say 20. Sensibly enough, the STL
algorithms have a function called <B>find_if(&#160;)</B> that will search
through a sequence; however, <B>find_if(&#160;)</B> requires a unary predicate
to tell it if this is what you&#8217;re looking for. This unary predicate can of
course be some function object that you have written by hand, but it can also be
created using the built-in function object templates. In this case, the
<B>less</B> template will work, but that produces a binary predicate, so we need
some way of forming a unary predicate. The binder templates (which work with any
binary function object, not just binary predicates) give you two
choices:</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><B>bind1st(const BinaryFunction&amp; op, const T&amp;
t);</B><BR><B>bind2nd(const BinaryFunction&amp; op, const T&amp;
t);</B><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Both bind <B>t </B>to one of the
arguments of <B>op</B>, but <B>bind1st(&#160;)</B> binds <B>t</B> to the first
argument, and <B>bind2nd(&#160;)</B> binds <B>t</B> to the second argument. With
<B>less</B>, the function object that provides the solution to our exercise
is:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>bind2nd(less&lt;<font color=#0000ff>int</font>&gt;(), 20);</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This produces a new function object that
returns true if its argument is less than 20. Here it is, used with
<B>find_if(&#160;)</B>:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:Binder1.cpp</font>
<font color=#009900>// Using STL "binders"</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-g++3}</font>
#include <font color=#004488>"Generators.h"</font>
#include <font color=#004488>"copy_if.h"</font>
#include &lt;algorithm&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;
#include &lt;functional&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>int</font> main() {
  <font color=#0000ff>const</font> <font color=#0000ff>int</font> sz = 10;
  <font color=#0000ff>const</font> <font color=#0000ff>int</font> max = 40;
  vector&lt;<font color=#0000ff>int</font>&gt; a(sz), r;
  URandGen urg(max);
  ostream_iterator&lt;<font color=#0000ff>int</font>&gt; out(cout, <font color=#004488>" "</font>);
  generate_n(a.begin(), sz, urg);
  copy(a.begin(), a.end(), out);
  <font color=#0000ff>int</font>* d = find_if(a.begin(), a.end(), 
    bind2nd(less&lt;<font color=#0000ff>int</font>&gt;(), 20));
  cout &lt;&lt; <font color=#004488>"\n *d = "</font> &lt;&lt; *d &lt;&lt; endl;
  <font color=#009900>// copy_if() is not in the Standard C++ library</font>
  <font color=#009900>// but is defined later in the chapter:</font>
  copy_if(a.begin(), a.end(), back_inserter(r),
    bind2nd(less&lt;<font color=#0000ff>int</font>&gt;(), 20));
  copy(r.begin(), r.end(), out);
  cout &lt;&lt; endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>vector&lt;int&gt;</B> <B>a</B> is
filled with random numbers between 0 and <B>max</B>. <B>find_if(&#160;)</B>
finds the first element in <B>a</B> that satisfies the predicate (that is, which
is less than 20) and returns an iterator to it (here, the type of the iterator
is actually just <B>int*</B> although I could have been more precise and said
<B>vector&lt;int&gt;::iterator</B> instead).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A more interesting algorithm to use is
<B>copy_if(&#160;)</B>, which isn&#8217;t part of the STL but is defined at the
end of this chapter. This algorithm only copies an element from the source to
the destination if that element satisfies a predicate. So the resulting vector
will only contain elements that are less than 20.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here&#8217;s a second example, using a
<B>vector&lt;string&gt;</B> and replacing strings that satisfy particular
conditions:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:Binder2.cpp</font>
<font color=#009900>// More binders</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include &lt;algorithm&gt;
#include &lt;vector&gt;
#include &lt;string&gt;
#include &lt;iostream&gt;
#include &lt;functional&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>int</font> main() {
  ostream_iterator&lt;string&gt; out(cout, <font color=#004488>" "</font>);
  vector&lt;string&gt; v, r;
  v.push_back(<font color=#004488>"Hi"</font>);
  v.push_back(<font color=#004488>"Hi"</font>);
  v.push_back(<font color=#004488>"Hey"</font>);
  v.push_back(<font color=#004488>"Hee"</font>);
  v.push_back(<font color=#004488>"Hi"</font>);
  copy(v.begin(), v.end(), out);
  cout &lt;&lt; endl;
  <font color=#009900>// Replace each "Hi" with "Ho":</font>
  replace_copy_if(v.begin(), v.end(), 
    back_inserter(r), 
    bind2nd(equal_to&lt;string&gt;(), <font color=#004488>"Hi"</font>), <font color=#004488>"Ho"</font>);
  copy(r.begin(), r.end(), out);
  cout &lt;&lt; endl;
  <font color=#009900>// Replace anything that's not "Hi" with "Ho":</font>
  replace_if(v.begin(), v.end(), 
    not1(bind2nd(equal_to&lt;string&gt;(),<font color=#004488>"Hi"</font>)),<font color=#004488>"Ho"</font>);
  copy(v.begin(), v.end(), out);
  cout &lt;&lt; endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This uses another pair of STL algorithms.
The first, <B>replace_copy_if(&#160;)</B>, copies each element from a source
range to a destination range, performing replacements on those that satisfy a
particular unary predicate. The second, <B>replace_if(&#160;)</B>, doesn&#8217;t
do any copying but instead performs the replacements directly into the original
range.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A binder doesn&#8217;t have to produce a
unary predicate; it can also create a unary function (that is, a function that
returns something other than <B>bool</B>). For example, suppose you&#8217;d like
to multiply every element in a <B>vector</B> by 10. Using a binder with the
<B>transform(&#160;)</B> algorithm does the trick:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:Binder3.cpp</font>
<font color=#009900>// Binders aren't limited to producing predicates</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <font color=#004488>"Generators.h"</font>
#include &lt;algorithm&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;
#include &lt;functional&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>int</font> main() {
  ostream_iterator&lt;<font color=#0000ff>int</font>&gt; out(cout, <font color=#004488>" "</font>);
  vector&lt;<font color=#0000ff>int</font>&gt; v(15);
  generate(v.begin(), v.end(), URandGen(20));
  copy(v.begin(), v.end(), out);
  cout &lt;&lt; endl;
  transform(v.begin(), v.end(), v.begin(),
    bind2nd(multiplies&lt;<font color=#0000ff>int</font>&gt;(), 10));
  copy(v.begin(), v.end(), out);
  cout &lt;&lt; endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Since the third argument to
<B>transform(&#160;) </B>is the same as the first, the resulting elements are
copied back into the source vector. The function object created by
<B>bind2nd(&#160;)</B> in this case produces an <B>int</B>
result.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The &#8220;bound&#8221; argument to a
binder cannot be a function object, but it does not have to be a compile-time
constant. For example:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:Binder4.cpp</font>
<font color=#009900>// The bound argument does not have </font>
<font color=#009900>// to be a compile-time constant</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-g++295}</font>
#include <font color=#004488>"copy_if.h"</font>
#include <font color=#004488>"PrintSequence.h"</font>
#include <font color=#004488>"..</font><font color=#004488>/require.h"</font>
#include &lt;iostream&gt;
#include &lt;algorithm&gt;
#include &lt;functional&gt;
#include &lt;cstdlib&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>int</font> boundedRand() { <font color=#0000ff>return</font> rand() % 100; }

<font color=#0000ff>int</font> main() {
  <font color=#0000ff>const</font> <font color=#0000ff>int</font> sz = 20;
  <font color=#0000ff>int</font> a[20], b[20] = {0};
  generate(a, a + sz, boundedRand);
  <font color=#0000ff>int</font> val = boundedRand();
  <font color=#0000ff>int</font>* end = copy_if(a, a + sz, b, bind2nd(greater&lt;<font color=#0000ff>int</font>&gt;(), val));
  <font color=#009900>// Sort for easier viewing:</font>
  sort(a, a + sz);
  sort(b, end);
  print(a, a + sz, <font color=#004488>"array a"</font>, <font color=#004488>" "</font>);
  print(b, end, <font color=#004488>"values greater than yours"</font>,<font color=#004488>" "</font>);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here, an array is filled with random
numbers between 0 and 100, and the user provides a value on the command line. In
the <B>copy_if(&#160;)</B> call, you can see that the bound argument to
<B>bind2nd(&#160;)</B> is the result of the function call <B>atoi(&#160;)</B>
(from <B>&lt;cstdlib&gt;</B>).</FONT><BR></P></DIV>
<A NAME="Heading252"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H4 ALIGN="LEFT">
Function pointer adapters</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Any place in an STL algorithm where a
function object is required, it&#8217;s very conceivable that you&#8217;d like
to use a function pointer instead. Actually, you <I>can</I> use an ordinary
function pointer &#8211; that&#8217;s how the STL was designed, so that a
&#8220;function object&#8221; can actually be anything that can be dereferenced
using an argument list. For example, the <B>rand(&#160;)</B> random number
generator can be passed to <B>generate(&#160;)</B> or <B>generate_n(&#160;)</B>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -