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

📄 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 页
字号:
<font color=#009900>// Probably a bug in this program:</font>
<font color=#009900>//{-msc}</font>
<font color=#009900>//{-bor} dumps core</font>
<font color=#009900>//{-g++295} dumps core</font>
<font color=#009900>//{-g++3} dumps core</font>
#include <font color=#004488>"..</font><font color=#004488>/require.h"</font>
#include &lt;algorithm&gt;
#include &lt;list&gt;
#include &lt;string&gt;
#include &lt;fstream&gt;
#include &lt;functional&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>typedef</font> list&lt;string&gt;::iterator LSI;

LSI blank(LSI begin, LSI end) {
   <font color=#0000ff>return</font> find_if(begin, end, 
     mem_fun_ref(&amp;string::empty));
}

<font color=#0000ff>int</font> main(<font color=#0000ff>int</font> argc, <font color=#0000ff>char</font>* argv[]) {
  <font color=#0000ff>char</font>* fname = <font color=#004488>"FindBlanks.cpp"</font>;
  <font color=#0000ff>if</font>(argc &gt; 1) fname = argv[1];
  ifstream in(fname);
  assure(in, fname);
  list&lt;string&gt; ls;
  string s;
  <font color=#0000ff>while</font>(getline(in, s))
    ls.push_back(s);
  LSI lsi = blank(ls.begin(), ls.end());
  <font color=#0000ff>while</font>(lsi != ls.end()) {
    *lsi = <font color=#004488>"A BLANK LINE"</font>;
    lsi = blank(lsi, ls.end());
  }
  string f(argv[1]);
  f += <font color=#004488>".out"</font>;
  ofstream out(f.c_str());
  copy(ls.begin(), ls.end(), 
    ostream_iterator&lt;string&gt;(out, <font color=#004488>"\n"</font>));
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>blank(&#160;)</B> function uses
<B>find_if(&#160;)</B> to locate the first blank line in the given range using
<B>mem_fun_ref(&#160;)</B> with <B>string::empty(&#160;)</B>. After the file is
opened and read into the <B>list</B>, <B>blank(&#160;)</B> is called repeated
times to find every blank line in the file. Notice that subsequent calls to
<B>blank(&#160;)</B> use the current version of the iterator so it moves forward
to the next one. Each time a blank line is found, it is replaced with the
characters &#8220;A BLANK LINE.&#8221; All you have to do to accomplish this is
dereference the iterator, and you select the current
<B>string</B>.</FONT><A NAME="_Toc519042062"></A><BR></P></DIV>
<A NAME="Heading253"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
SGI extensions</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The SGI STL (mentioned at the end of the
previous chapter) also includes additional function object templates, which
allow you to write expressions that create even more complicated function
objects. Consider a more involved program which converts strings of digits into
floating point numbers, like <B>PtrFun2.cpp</B> but more general. First,
here&#8217;s a generator that creates strings of integers that represent
floating-point values (including an embedded decimal point):</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:NumStringGen.h</font>
<font color=#009900>// A random number generator that produces </font>
<font color=#009900>// strings representing floating-point numbers</font>
#ifndef NUMSTRINGGEN_H
#define NUMSTRINGGEN_H
#include &lt;string&gt;
#include &lt;cstdlib&gt;
#include &lt;ctime&gt;

<font color=#0000ff>class</font> NumStringGen {
  <font color=#0000ff>const</font> <font color=#0000ff>int</font> sz; <font color=#009900>// Number of digits to make</font>
<font color=#0000ff>public</font>:
  NumStringGen(<font color=#0000ff>int</font> ssz = 5) : sz(ssz) { 
    std::srand(std::time(0)); 
  }
  std::string <font color=#0000ff>operator</font>()() {
    <font color=#0000ff>static</font> <font color=#0000ff>char</font> n[] = <font color=#004488>"0123456789"</font>;
    <font color=#0000ff>const</font> <font color=#0000ff>int</font> nsz = 10;
    std::string r(sz, ' ');
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; sz; i++)
      <font color=#0000ff>if</font>(i == sz/2)
        r[i] = '.'; <font color=#009900>// Insert a decimal point</font>
      <font color=#0000ff>else</font>
        r[i] = n[std::rand() % nsz];
    <font color=#0000ff>return</font> r;
  }
};
#endif <font color=#009900>// NUMSTRINGGEN_H ///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You tell it how big the <B>string</B>s
should be when you create the <B>NumStringGen</B> object. The random number
generator is used to select digits, and a decimal point is placed in the
middle.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The following program (which works with
the Standard C++ STL without the SGI extensions) uses <B>NumStringGen</B> to
fill a <B>vector&lt;string&gt;</B>. However, to use the Standard C library
function <B>atof(&#160;)</B> to convert the strings to floating-point numbers,
the <B>string</B> objects must first be turned into <B>char</B> pointers, since
there is no automatic type conversion from <B>string</B> to <B>char*</B>. The
<B>transform(&#160;)</B> algorithm can be used with <B>mem_fun_ref(&#160;)</B>
and <B>string::c_str(&#160;)</B> to convert all the <B>string</B>s to
<B>char*</B>, and then these can be transformed using
<B>atof</B>:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:MemFun3.cpp</font>
<font color=#009900>// Using mem_fun()</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-msc}</font>
#include <font color=#004488>"NumStringGen.h"</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() {
  <font color=#0000ff>const</font> <font color=#0000ff>int</font> sz = 9;
  vector&lt;string&gt; vs(sz);
  <font color=#009900>// Fill it with random number strings:</font>
  generate(vs.begin(), vs.end(), NumStringGen());
  copy(vs.begin(), vs.end(), 
    ostream_iterator&lt;string&gt;(cout, <font color=#004488>"\t"</font>));
  cout &lt;&lt; endl;
  <font color=#0000ff>const</font> <font color=#0000ff>char</font>* vcp[sz];
  transform(vs.begin(), vs.end(), vcp, 
    mem_fun_ref(&amp;string::c_str));
  vector&lt;<font color=#0000ff>double</font>&gt; vd;
  transform(vcp,vcp + sz,back_inserter(vd),
    std::atof);
  copy(vd.begin(), vd.end(), 
    ostream_iterator&lt;<font color=#0000ff>double</font>&gt;(cout, <font color=#004488>"\t"</font>));
  cout &lt;&lt; endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The SGI extensions to the STL contain a
number of additional function object templates that accomplish more detailed
activities than the Standard C++ function object templates, including
<B>identity </B>(returns its argument unchanged), <B>project1st</B> and
<B>project2nd</B> (to take two arguments and return the first or second one,
respectively), <B>select1st</B> and <B>select2nd</B> (to take a <B>pair</B>
object and return the first or second element, respectively), and the
&#8220;compose&#8221; function templates.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">If you&#8217;re using the SGI extensions,
you can make the above program denser using one of the two &#8220;compose&#8221;
function templates. The first, <B>compose1(f1,&#160;f2)</B>, takes the two
function objects <B>f1 </B>and <B>f2 </B>as its arguments. It produces a
function object that takes a single argument, passes it to <B>f2</B>, then takes
the result of the call to <B>f2</B> and passes it to <B>f1</B>. The result of
<B>f1</B> is returned. By using <B>compose1(&#160;)</B>, the process of
converting the <B>string</B> objects to <B>char*</B>, then converting the
<B>char*</B> to a floating-point number can be combined into a single operation,
like this:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:MemFun4.cpp</font>
<font color=#009900>// Using the SGI STL compose1 function</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-bor} Can add the header by hand</font>
<font color=#009900>//{-msc} Can add the header by hand</font>
#include <font color=#004488>"NumStringGen.h"</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() {
  <font color=#0000ff>const</font> <font color=#0000ff>int</font> sz = 9;
  vector&lt;string&gt; vs(sz);
  <font color=#009900>// Fill it with random number strings:</font>
  generate(vs.begin(), vs.end(), NumStringGen());
  copy(vs.begin(), vs.end(), 
    ostream_iterator&lt;string&gt;(cout, <font color=#004488>"\t"</font>));
  cout &lt;&lt; endl;
  vector&lt;<font color=#0000ff>double</font>&gt; vd;
  transform(vs.begin(), vs.end(), back_inserter(vd),
    compose1(ptr_fun(atof), 
      mem_fun_ref(&amp;string::c_str)));
  copy(vd.begin(), vd.end(), 
    ostream_iterator&lt;<font color=#0000ff>double</font>&gt;(cout, <font color=#004488>"\t"</font>));
  cout &lt;&lt; endl;
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see there&#8217;s only a single
call to <B>transform(&#160;)</B> now, and no intermediate holder for the
<B>char</B> pointers.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The second &#8220;compose&#8221; function
is <B>compose2(&#160;)</B>, which takes three function objects as its arguments.
The first function object is binary (it takes two arguments), and its arguments
are the results of the second and third function objects, respectively. The
function object that results from <B>compose2(&#160;)</B> expects one argument,
and it feeds that argument to the second and third function objects. Here is an
example:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:Compose2.cpp</font>
<font color=#009900>// Using the SGI STL compose2() function</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-bor} Can add the header by hand</font>
<font color=#009900>//{-msc} Can add the header by hand</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;
#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() {
  srand(time(0));
  vector&lt;<font color=#0000ff>int</font>&gt; v(100);
  generate(v.begin(), v.end(), rand);
  transform(v.begin(), v.end(), v.begin(),
    bind2nd(divides&lt;<font color=#0000ff>int</font>&gt;(), RAND_MAX/100));
  vector&lt;<font color=#0000ff>int</font>&gt; r;
  copy_if(v.begin(), v.end(), back_inserter(r),
    compose2(logical_and&lt;<font color=#0000ff>bool</font>&gt;(),
      bind2nd(greater_equal&lt;<font color=#0000ff>int</font>&gt;(), 30),
      bind2nd(less_equal&lt;<font color=#0000ff>int</font>&gt;(), 40)));
  sort(r.begin(), r.end());
  copy(r.begin(), r.end(),
    ostream_iterator&lt;<font color=#0000ff>int</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">The <B>vector&lt;int&gt; v</B> is first
filled with random numbers. To cut these down to size, the
<B>transform(&#160;)</B> algorithm is used to divide each value by
<B>RAND_MAX/100</B>, which will force the values to be between 0 and 100 (making
them more readable). The <B>copy_if(&#160;)</B> algorithm defined later in this
chapter is then used, along with a composed function object, to copy all the
elements that are greater than or equal to 30 and less than or equal to 40 into
the destination <B>vector&lt;int&gt; r</B>. Just to show how easy it is,
<B>r</B> is sorted, and then displayed.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The arguments of <B>compose2(&#160;)</B>
say, in effect:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>(x &gt;= 30) &amp;&amp; (x &lt;= 40)</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You could also take the function object
that comes from a <B>compose1(&#160;)</B> or <B>compose2(&#160;)</B> call and
pass it into another &#8220;compose&#8221; expression ... but this could rapidly
get very difficult to decipher.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Instead of all this composing and
transforming, you can write your own function objects (<I>without </I>using the
SGI extensions) as follows:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C08:NoCompose.cpp</font>
<font color=#009900>// Writing out the function objects explicitly</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <font color=#004488>"copy_if.h"</font>
#include &lt;algorithm&gt;
#include &lt;vector&gt;
#include &lt;string&gt;
#include &lt;iostream&gt;
#include &lt;func

⌨️ 快捷键说明

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