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

📄 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 页
字号:
as a function pointer, like this:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:RandGenTest.cpp</font>
<font color=#009900>// A little test of the random number generator</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-msc}</font>
#include &lt;algorithm&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;
#include &lt;functional&gt;
#include &lt;cstdlib&gt;
#include &lt;ctime&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 = 10000;
  <font color=#0000ff>int</font> v[sz];
  srand(time(0)); <font color=#009900>// Seed the random generator</font>
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 300; i++) {
    <font color=#009900>// Using a naked pointer to function:</font>
    generate(v, v + sz, std::rand);
    <font color=#0000ff>int</font> count = count_if(v, v + sz, 
      bind2nd(greater&lt;<font color=#0000ff>int</font>&gt;(), RAND_MAX/2));
    cout &lt;&lt; (((<font color=#0000ff>double</font>)count)/((<font color=#0000ff>double</font>)sz)) * 100
      &lt;&lt; ' ';
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The &#8220;iterators&#8221; in this case
are just the starting and past-the-end pointers for the array <B>v</B>, and the
generator is just a pointer to the standard library <B>rand(&#160;)</B>
function. The program repeatedly generates a group of random numbers, then it
uses the STL algorithm <B>count_if(&#160;)</B> and a predicate that tells
whether a particular element is greater than <B>RAND_MAX/2</B>. The result is
the number of elements that match this criterion; this is divided by the total
number of elements and multiplied by 100 to produce the percentage of elements
greater than the midpoint. If the random number generator is reasonable, this
value should hover at around 50% (of course, there are many other tests to
determine if the random number generator is reasonable).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>ptr_fun(&#160;) </B>adapters take
a pointer to a function and turn it into a function object. They are not
designed for a function that takes no arguments, like the one above (that is, a
generator). Instead, they are for unary functions and binary functions. However,
these could also be simply passed as if they were function objects, so the
<B>ptr_fun(&#160;)</B> adapters might at first appear to be redundant.
Here&#8217;s an example where using <B>ptr_fun(&#160;)</B> and simply passing
the address of the function both produce the same results:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:PtrFun1.cpp</font>
<font color=#009900>// Using ptr_fun() for single-argument functions</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-bor}</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>char</font>* n[] = { <font color=#004488>"01.23"</font>, <font color=#004488>"91.370"</font>, <font color=#004488>"56.661"</font>,
  <font color=#004488>"023.230"</font>, <font color=#004488>"19.959"</font>, <font color=#004488>"1.0"</font>, <font color=#004488>"3.14159"</font> };
<font color=#0000ff>const</font> <font color=#0000ff>int</font> nsz = <font color=#0000ff>sizeof</font> n / <font color=#0000ff>sizeof</font> *n;

<font color=#0000ff>template</font>&lt;<font color=#0000ff>typename</font> InputIter&gt;
<font color=#0000ff>void</font> print(InputIter first, InputIter last) {
  <font color=#0000ff>while</font>(first != last)
    cout &lt;&lt; *first++ &lt;&lt; <font color=#004488>"\t"</font>;
  cout &lt;&lt; endl;
}

<font color=#0000ff>int</font> main() {
  print(n, n + nsz);
  vector&lt;<font color=#0000ff>double</font>&gt; vd;
  transform(n, n + nsz, back_inserter(vd), atof);
  print(vd.begin(), vd.end());
  transform(n,n + nsz,vd.begin(), ptr_fun(atof));
  print(vd.begin(), vd.end());
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The goal of this program is to convert an
array of <B>char*</B> which are ASCII representations of floating-point numbers
into a <B>vector&lt;double&gt;</B>. After defining this array and the
<B>print(&#160;)</B> template (which encapsulates the act of printing a range of
elements), you can see <B>transform(&#160;)</B> used with <B>atof(&#160;)</B> as
a &#8220;naked&#8221; pointer to a function, and then a second time with
<B>atof</B> passed to <B>ptr_fun(&#160;)</B>. The results are the same. So why
bother with <B>ptr_fun(&#160;)</B>? Well, the actual effect of
<B>ptr_fun(&#160;)</B> is to create a function object with an
<B>operator(&#160;)</B>. This function object can then be passed to other
template adapters, such as binders, to create new function objects. As
you&#8217;ll see a bit later, the SGI extensions to the STL contain a number of
other function templates to enable this, but in the Standard C++ STL there are
only the <B>bind1st(&#160;)</B> and <B>bind2nd(&#160;)</B> function templates,
and these expect binary function objects as their first arguments. In the above
example, only the <B>ptr_fun(&#160;)</B> for a unary function is used, and that
doesn&#8217;t work with the binders. So <B>ptr_fun(&#160;)</B> used with a unary
function in Standard C++ really is redundant (note that Gnu g++ uses the SGI
STL).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">With a binary function and a binder,
things can be a little more interesting. This program produces the squares of
the input vector <B>d</B>:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:PtrFun2.cpp</font>
<font color=#009900>// Using ptr_fun() for two-argument functions</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-bor}</font>
<font color=#009900>//{-g++3}</font>
#include &lt;algorithm&gt;
#include &lt;vector&gt;
#include &lt;iostream&gt;
#include &lt;functional&gt;
#include &lt;cmath&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>double</font> d[] = { 01.23, 91.370, 56.661,
  023.230, 19.959, 1.0, 3.14159 };
<font color=#0000ff>const</font> <font color=#0000ff>int</font> dsz = <font color=#0000ff>sizeof</font> d / <font color=#0000ff>sizeof</font> *d;

<font color=#0000ff>int</font> main() {
  vector&lt;<font color=#0000ff>double</font>&gt; vd;
  transform(d, d + dsz, back_inserter(vd), 
    bind2nd(ptr_fun(pow), 2.0));
  copy(vd.begin(), vd.end(),
    ostream_iterator&lt;<font color=#0000ff>double</font>&gt;(cout, <font color=#004488>" "</font>));
  cout &lt;&lt; endl;    
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here, <B>ptr_fun(&#160;)</B> is
indispensable; <B>bind2nd(&#160;)</B> <I>must</I> have a function object as its
first argument and a pointer to function won&#8217;t cut it.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A trickier problem is that of converting
a member function into a function object suitable for using in the STL
algorithms. As a simple example, suppose we have the &#8220;shape&#8221; problem
and would like to apply the <B>draw(&#160;)</B> member function to each pointer
in a container of <B>Shape</B>:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:MemFun1.cpp</font>
<font color=#009900>// Applying pointers to member functions</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-msc}</font>
#include <font color=#004488>"..</font><font color=#004488>/purge.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>class</font> Shape {
<font color=#0000ff>public</font>:
  <font color=#0000ff>virtual</font> <font color=#0000ff>void</font> draw() = 0;
  <font color=#0000ff>virtual</font> ~Shape() {}
};

<font color=#0000ff>class</font> Circle : <font color=#0000ff>public</font> Shape {
<font color=#0000ff>public</font>:
  <font color=#0000ff>virtual</font> <font color=#0000ff>void</font> draw() {
    cout &lt;&lt; <font color=#004488>"Circle::Draw()"</font> &lt;&lt; endl;
  }
  ~Circle() {
    cout &lt;&lt; <font color=#004488>"Circle::~Circle()"</font> &lt;&lt; endl;
  }
};

<font color=#0000ff>class</font> Square : <font color=#0000ff>public</font> Shape {
<font color=#0000ff>public</font>:
  <font color=#0000ff>virtual</font> <font color=#0000ff>void</font> draw() {
    cout &lt;&lt; <font color=#004488>"Square::Draw()"</font> &lt;&lt; endl;
  }
  ~Square() {
    cout &lt;&lt; <font color=#004488>"Square::~Square()"</font> &lt;&lt; endl;
  }
};

<font color=#0000ff>int</font> main() {
  vector&lt;Shape*&gt; vs;
  vs.push_back(<font color=#0000ff>new</font> Circle);
  vs.push_back(<font color=#0000ff>new</font> Square);
  for_each(vs.begin(), vs.end(), 
    mem_fun(&amp;Shape::draw));
  purge(vs);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>for_each(&#160;)</B> function does
just what it sounds like it does: passes each element in the range determined by
the first two (iterator) arguments to the function object which is its third
argument. In this case we want the function object to be created from one of the
member functions of the class itself, and so the function object&#8217;s
&#8220;argument&#8221; becomes the pointer to the object that the member
function is called for. To produce such a function object, the
<B>mem_fun(&#160;)</B> template takes a pointer to member as its
argument.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>mem_fun(&#160;)</B> functions are
for producing function objects that are called using a pointer to the object
that the member function is called for, while <B>mem_fun_ref(&#160;)</B> is used
for calling the member function directly for an object. One set of overloads of
both <B>mem_fun(&#160;)</B> and <B>mem_fun_ref(&#160;)</B> are for member
functions that take zero arguments and one argument, and this is multiplied by
two to handle <B>const</B> vs. non-<B>const</B> member functions. However,
templates and overloading takes care of sorting all of that out; all you need to
remember is when to use <B>mem_fun(&#160;)</B> vs.
<B>mem_fun_ref(&#160;)</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Suppose you have a container of objects
(not pointers) and you want to call a member function that takes an argument.
The argument you pass should come from a second container of objects. To
accomplish this, the second overloaded form of the <B>transform(&#160;)</B>
algorithm is used:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:MemFun2.cpp</font>
<font color=#009900>// Applying pointers to member functions</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-msc}</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>class</font> Angle {
  <font color=#0000ff>int</font> degrees;
<font color=#0000ff>public</font>:
  Angle(<font color=#0000ff>int</font> deg) : degrees(deg) {}
  <font color=#0000ff>int</font> mul(<font color=#0000ff>int</font> times) {
    <font color=#0000ff>return</font> degrees *= times;
  }
};

<font color=#0000ff>int</font> main() {
  vector&lt;Angle&gt; va;
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 50; i += 10)
    va.push_back(Angle(i));
  <font color=#0000ff>int</font> x[] = { 1, 2, 3, 4, 5 };
  transform(va.begin(), va.end(), x,
    ostream_iterator&lt;<font color=#0000ff>int</font>&gt;(cout, <font color=#004488>" "</font>),
    mem_fun_ref(&amp;Angle::mul));
  cout &lt;&lt; endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because the container is holding objects,
<B>mem_fun_ref(&#160;)</B> must be used with the pointer-to-member function.
This version of <B>transform(&#160;)</B> takes the start and end point of the
first range (where the objects live), the starting point of second range which
holds the arguments to the member function, the destination iterator which in
this case is standard output, and the function object to call for each object;
this function object is created with <B>mem_fun_ref(&#160;)</B> and the desired
pointer to member. Notice the <B>transform(&#160;)</B> and
<B>for_each(&#160;)</B> template functions are incomplete;
<B>transform(&#160;)</B> requires that the function it calls return a value and
there is no <B>for_each(&#160;)</B> that passes two arguments to the function it
calls. Thus, you cannot call a member function that returns <B>void</B> and
takes an argument using <B>transform(&#160;)</B> or
<B>for_each(&#160;)</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Any member function works, including
those in the Standard libraries. For example, suppose you&#8217;d like to read a
file and search for blank lines; you can use the <B>string::empty(&#160;)</B>
member function like this:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:FindBlanks.cpp</font>
<font color=#009900>// Demonstrate mem_fun_ref() with string::empty()</font>
<font color=#009900>//{L} ../TestSuite/Test</font>

⌨️ 快捷键说明

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