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

📄 chap06.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>// Uses template type induction to </font>
<font color=#009900>// discover the size of an array</font>
#ifndef ARRAYSIZE_H
#define ARRAYSIZE_H

<font color=#0000ff>template</font>&lt;<font color=#0000ff>typename</font> T, <font color=#0000ff>int</font> size&gt;
<font color=#0000ff>int</font> asz(T (&amp;)[size]) { <font color=#0000ff>return</font> size; }

#endif <font color=#009900>// ARRAYSIZE_H ///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This actually figures out the size of an
array as a compile-time constant value, without using any <B>sizeof(&#160;)</B>
operations! Thus you can have a much more succinct way to calculate the size of
an array at compile time:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:ArraySize.cpp</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-msc}</font>
<font color=#009900>//{-bor}</font>
<font color=#009900>// The return value of the template function</font>
<font color=#009900>// asz() is a compile-time constant</font>
#include <font color=#004488>"..</font><font color=#004488>/arraySize.h"</font>

<font color=#0000ff>int</font> main() {
  <font color=#0000ff>int</font> a[12], b[20];
  <font color=#0000ff>const</font> <font color=#0000ff>int</font> sz1 = asz(a);
  <font color=#0000ff>const</font> <font color=#0000ff>int</font> sz2 = asz(b);
  <font color=#0000ff>int</font> c[sz1], d[sz2];
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Of course, just making a variable of a
built-in type a <B>const</B> does not guarantee it&#8217;s actually a
compile-time constant, but if it&#8217;s used to define the size of an array (as
it is in the last line of <B>main(&#160;)</B>), then it <I>must</I> be a
compile-time constant.</FONT><A NAME="_Toc519041984"></A><BR></P></DIV>
<A NAME="Heading161"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Taking the address of a generated function template </H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There are a number of situations where
you need to take the address of a function. For example, you may have a function
that takes an argument of a pointer to another function. Of course it&#8217;s
possible that this other function might be generated from a template function so
you need some way to take that kind of
address</FONT><A NAME="fnB16" HREF="#fn16">[16]</A><FONT FACE="Georgia">:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:TemplateFunctionAddress.cpp</font>
<font color=#009900>// Taking the address of a function generated</font>
<font color=#009900>// from a template.</font>
<font color=#009900>//{L} ../TestSuite/Test</font>

<font color=#0000ff>template</font> &lt;<font color=#0000ff>typename</font> T&gt; <font color=#0000ff>void</font> f(T*) {}

<font color=#0000ff>void</font> h(<font color=#0000ff>void</font> (*pf)(<font color=#0000ff>int</font>*)) {}

<font color=#0000ff>template</font> &lt;<font color=#0000ff>class</font> T&gt; 
  <font color=#0000ff>void</font> g(<font color=#0000ff>void</font> (*pf)(T*)) {}

<font color=#0000ff>int</font> main() {
  <font color=#009900>// Full type exposition:</font>
  h(&amp;f&lt;<font color=#0000ff>int</font>&gt;);
  <font color=#009900>// Type induction:</font>
  h(&amp;f);
  <font color=#009900>// Full type exposition:</font>
  g&lt;<font color=#0000ff>int</font>&gt;(&amp;f&lt;<font color=#0000ff>int</font>&gt;);
  <font color=#009900>// Type inductions:</font>
  g(&amp;f&lt;<font color=#0000ff>int</font>&gt;);
  g&lt;<font color=#0000ff>int</font>&gt;(&amp;f);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This example demonstrates a number of
different issues. First, even though you&#8217;re using templates, the
signatures must match &#8211; the function <B>h(&#160;)</B> takes a pointer to a
function that takes an <B>int*</B> and returns <B>void</B>, and that&#8217;s
what the template <B>f</B> produces. Second, the function that wants the
function pointer as an argument can itself be a template, as in the case of the
template <B>g</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In <B>main(&#160;)</B> you can see that
type induction works here, too. The first call to <B>h(&#160;)</B> explicitly
gives the template argument for <B>f</B>, but since <B>h(&#160;)</B> says that
it will only take the address of a function that takes an <B>int*</B>, that part
can be induced by the compiler. With <B>g(&#160;)</B> the situation is even more
interesting because there are two templates involved. The compiler cannot induce
the type with nothing to go on, but if either <B>f</B> or <B>g</B> is given
<B>int</B>, then the rest can be
induced.</FONT><A NAME="_Toc312374091"></A><A NAME="_Toc519041985"></A><BR></P></DIV>
<A NAME="Heading162"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Local classes in templates<A NAME="_Toc519041986"></A></H2></FONT>
<A NAME="Heading163"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Applying a function to an STL
sequence<BR><A NAME="Index472"></A><A NAME="Index473"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Suppose you want to take an STL sequence
container (which you&#8217;ll learn more about in subsequent chapters; for now
we can just use the familiar <B>vector</B>) and apply a function to all the
objects it contains. Because a <B>vector</B> can contain any type of object, you
need a function that works with any type of <B>vector</B> and any type of object
it contains:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:applySequence.h</font>
<font color=#009900>// Apply a function to an STL sequence container</font>

<font color=#009900>// 0 arguments, any type of return value:</font>
<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> Seq, <font color=#0000ff>class</font> T, <font color=#0000ff>class</font> R&gt;
<font color=#0000ff>void</font> apply(Seq&amp; sq, R (T::*f)()) {
  <font color=#0000ff>typename</font> Seq::iterator it = sq.begin();
  <font color=#0000ff>while</font>(it != sq.end()) {
    ((*it)-&gt;*f)();
    it++;
  }
}

<font color=#009900>// 1 argument, any type of return value:</font>
<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> Seq, <font color=#0000ff>class</font> T, <font color=#0000ff>class</font> R, <font color=#0000ff>class</font> A&gt;
<font color=#0000ff>void</font> apply(Seq&amp; sq, R(T::*f)(A), A a) {
  <font color=#0000ff>typename</font> Seq::iterator it = sq.begin();
  <font color=#0000ff>while</font>(it != sq.end()) {
    ((*it)-&gt;*f)(a);
    it++;
  }
}

<font color=#009900>// 2 arguments, any type of return value:</font>
<font color=#0000ff>template</font>&lt;<font color=#0000ff>class</font> Seq, <font color=#0000ff>class</font> T, <font color=#0000ff>class</font> R, 
         <font color=#0000ff>class</font> A1, <font color=#0000ff>class</font> A2&gt;
<font color=#0000ff>void</font> apply(Seq&amp; sq, R(T::*f)(A1, A2),
    A1 a1, A2 a2) {
  <font color=#0000ff>typename</font> Seq::iterator it = sq.begin();
  <font color=#0000ff>while</font>(it != sq.end()) {
    ((*it)-&gt;*f)(a1, a2);
    it++;
  }
}
<font color=#009900>// Etc., to handle maximum likely arguments ///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>apply(&#160;) </B>function
template takes a reference to the container class and a pointer-to-member for a
member function of the objects contained in the class. It uses an iterator to
move through the <B>Stack</B> and apply the function to every object. If
you&#8217;ve (understandably) forgotten the
pointer-to-member<A NAME="Index474"></A> syntax, you can refresh your memory at
the end of Chapter XX.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Notice that there are no STL header files
(or any header files, for that matter) included in <B>applySequence.h</B>, so it
is actually not limited to use with an STL sequence. However, it does make
assumptions (primarily, the name and behavior of the <B>iterator</B>) that apply
to STL sequences.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see there is more than one
version of <B>apply(&#160;)</B>, so it&#8217;s possible to overload function
templates. Although they all take any type of return value (which is ignored,
but the type information is required to match the pointer-to-member), each
version takes a different number of arguments, and because it&#8217;s a
template, those arguments can be of any type. The only limitation here is that
there&#8217;s no &#8220;super template&#8221; to create templates for you; thus
you must decide how many arguments will ever be required.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To test the various overloaded versions
of <B>apply(&#160;)</B>, the class
<B>Gromit</B></FONT><A NAME="fnB17" HREF="#fn17">[17]</A><A NAME="Index475"></A><FONT FACE="Georgia">
is created containing functions with different numbers of
arguments:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:Gromit.h</font>
<font color=#009900>// The techno-dog. Has member functions </font>
<font color=#009900>// with various numbers of arguments.</font>
#include &lt;iostream&gt;

<font color=#0000ff>class</font> Gromit { 
  <font color=#0000ff>int</font> arf;
<font color=#0000ff>public</font>:
  Gromit(<font color=#0000ff>int</font> arf = 1) : arf(arf + 1) {}
  <font color=#0000ff>void</font> speak(<font color=#0000ff>int</font>) {
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; arf; i++)
      std::cout &lt;&lt; <font color=#004488>"arf! "</font>;
    std::cout &lt;&lt; std::endl;
  }
  <font color=#0000ff>char</font> eat(<font color=#0000ff>float</font>) {
    std::cout &lt;&lt; <font color=#004488>"chomp!"</font> &lt;&lt; std::endl;
    <font color=#0000ff>return</font> 'z';
  }
  <font color=#0000ff>int</font> sleep(<font color=#0000ff>char</font>, <font color=#0000ff>double</font>) {
    std::cout &lt;&lt; <font color=#004488>"zzz..."</font> &lt;&lt; std::endl;
    <font color=#0000ff>return</font> 0;
  }
  <font color=#0000ff>void</font> sit(<font color=#0000ff>void</font>) {}
}; <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Now the <B>apply(&#160;)</B> template
functions can be combined with a <B>vector&lt;Gromit*&gt;</B> to make a
container that will call member functions of the contained objects, like
this:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:applyGromit.cpp</font>
<font color=#009900>// Test applySequence.h</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <font color=#004488>"Gromit.h"</font>
#include <font color=#004488>"applySequence.h"</font>
#include &lt;vector&gt;
#include &lt;iostream&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#0000ff>int</font> main() {
  vector&lt;Gromit*&gt; dogs;
  <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 5; i++)
    dogs.push_back(<font color=#0000ff>new</font> Gromit(i));
  apply(dogs, &amp;Gromit::speak, 1);
  apply(dogs, &amp;Gromit::eat, 2.0f);
  apply(dogs, &amp;Gromit::sleep, 'z', 3.0);
  apply(dogs, &amp;Gromit::sit);
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Although the definition of
<B>apply(&#160;)</B> is somewhat complex and not something you&#8217;d ever
expect a novice to understand, its use is remarkably clean and simple, and a
novice could easily use it knowing only<I> what</I> it is intended to
accomplish, not <I>how</I>. This is the type of division you should strive for
in all of your program components: The tough details are all isolated on the
designer&#8217;s side of the wall, and users are concerned only with
accomplishing their goals, and don&#8217;t see, know about, or depend on details
of the underlying
implementation</FONT><A NAME="_Toc312374092"></A><A NAME="_Toc519041987"></A><BR></P></DIV>
<A NAME="Heading164"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Expression templates<A NAME="_Toc519041988"></A></H2></FONT>
<A NAME="Heading165"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Template-templates</H2></FONT>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C06:TemplateTemplate.cpp</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
<font color=#009900>//{-msc}</font>
#include &lt;vector&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;

<font color=#009900>// As long as things are simple, </font>
<font color=#009900>// this approach works fine:</font>
<font color=#0000ff>template</font>&lt;<font color=#0000ff>typename</font> C&gt;
<font color=#0000ff>void</font> print1(C&amp; c) {
  <font color=#0000ff>typename</font> C::iterator it;
  <font color=#0000ff>for</font>(it = c.begin(); it != c.end(); it++)
    cout &lt;&lt; *it &lt;&lt; <font color=#004488>" "</font>;
  cout &lt;&lt; endl;
}

⌨️ 快捷键说明

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