home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 14 Text / 14-Text.zip / bithancc.zip / BIT-CPP2.C63
Text File  |  1994-03-28  |  42KB  |  1,352 lines

  1. *****  Computer Select, March 1994  : Articles *****
  2.  
  3. Journal:    C Users Journal  Jan 1994 v12 n1 p91(19)
  4. COPYRIGHT R & D Publications Inc. 1994
  5. -------------------------------------------------------------------------
  6. Title:     Bit handling in C++, part 2.
  7.              (includes related article on function and class templates)
  8.              (Code Capsules)
  9. Author:    Allison, Chuck
  10.  
  11.  
  12. Abstract:  The bits class is one of two classes of the standard C++
  13.            library, which allows easy access to bits, adds important
  14.            functionality and allows a fixed and arbitrary number of bits
  15.            in a bitset. Descriptions for each member function are
  16.            provided via a modified excerpt from the official proposal.
  17.            Listing 1 provides a function template for swapping objects of
  18.            the same type. Listing 2 provides a class for a stack of
  19.            integers. Listing 3 provides out-of-line functions for the
  20.            stack class. Listing 4 gives a class template for homogeneous
  21.            stacks and Listing 5 illustrates the stack template class.
  22.            Listings 6 and 7 describe the bits class template interface
  23.            and an implementation of this class. Having an expression as a
  24.            template parameter allows a bits-object to be stack-based,
  25.            resulting in better performance than bitstring objects. The
  26.            bits class also includes a set of integers.
  27. -------------------------------------------------------------------------
  28. Full Text:
  29.  
  30. The bits Class Template
  31.  
  32. The standard C++ library has two classes for bit manipulation: bitstring
  33. and bits. Last month I discussed the bitstring class, which defines
  34. objects that behave like an array of bits that expands or contracts
  35. according to your needs. This month's installment explains the bits
  36. class, an abstraction which extends C's bitwise semantics by allowing
  37. easy access to bits, by allowing an arbitrary (but fixed) number of bits
  38. in a bitset, and by adding important new functionality. Following last
  39. month's format, I present here an excerpt from the official proposal
  40. accepted by the standards committee, a working implementation, and
  41. examples of how to use the class.
  42.  
  43. Class bits accommodates a fixed-length collection of bits. You can think
  44. of a bits object as an arbitrarily large unsigned integer. It is actually
  45. a class template, with a number of bits in the collection as the template
  46. parameter. (See the sidebar "Templates in a Nutshall.") It is highly
  47. suitable for interfacing with the host operating system, and is designed
  48. for efficiency. (It can be stack-based.) Here's a sample program run on a
  49. machine with 16-bit integers:
  50.  
  51. // tbits.ccp:
  52.  
  53. // Set some bits // and display the result - #include <iostream.h>
  54. #include <stddef.h> #include <limits.h> #include "bits.h"
  55.  
  56. main() { const size[underscore]t SIZE = CHAR[underscore]BIT *
  57. sizeof(int); bits<SIZE> flags; enum open[underscore]mode {in, out, ate,
  58. app, trunc, binary};
  59.  
  60. flags.set(in); flags.set(binary); cout << "flags << " (0x" << hex <<
  61. flags.to[underscore]ushort() << ")/n"; cout << "binary? " <<
  62. (flags.test(binary) ? "yes" : "no") << end1; return 0;
  63.  
  64. }
  65.  
  66. Output flats: 0000000000100001 (0x21) binary? yes
  67.  
  68. Member Function Descriptions
  69.  
  70. This section is a modified excerpt from the official proposal which
  71. describes the semantics of each member function. For a quick look at the
  72. class interface, see Listing 6. Since the library group of the joint C++
  73. standards committee is still deciding how to integrate exceptions into
  74. the standard library, I just mention them briefly here. The names and
  75. uses of exceptions are subject to change. I use asserts in place of
  76. exceptions in the implementation (see Listing 7).
  77.  
  78. 1.0 Constructors
  79.  
  80. Synopsis bits() bits(unsigned long n) bits(const string& s) bits(const
  81. bits<N>& b)
  82.  
  83. 1.1 Constructor bits()
  84.  
  85. Description
  86.  
  87. Initializes all bits to zero.
  88.  
  89. 1.2 Constructor bits(unsigned long n)
  90.  
  91. Description
  92.  
  93. Initializes the object with the bits of n. If N >sizeof(unsigned long) *
  94. CHAR[underscore]BIT, sets the extra bits to zero.
  95.  
  96. 1.3 Constructor bits (const string& s)
  97.  
  98. Description
  99.  
  100. Each character of s is interpreted as a bit ( a string of 1s and 0s is
  101. expected). In typical integral fashion, treats the last (right-most)
  102. character of s as bit 0.
  103.  
  104. Exceptions
  105.  
  106. Throws invalid[underscore]argument if a character other than 1 or 0 is
  107. encountered.
  108.  
  109. 1.4 Constructor bits(const bits<N>& b)
  110.  
  111. Description
  112.  
  113. Standard copy constructor.
  114.  
  115. 2.0 Destructor No destructor required.
  116.  
  117. 3.0 Other Member Functions
  118.  
  119. 3.1 Function unsigned short to[underscore]ushort() const
  120.  
  121. Description
  122.  
  123. Converts the n least significant bits of *this (where n ==
  124. sizeof(unsigned short) * CHAR[underscore]BIT) to an unsigned short. This
  125. is useful when the bits represent flags in a word passed to the operating
  126. system.
  127.  
  128. Exceptions
  129.  
  130. Throws overflow iof N > n and any of the bits above position n-1 are set.
  131.  
  132. 3.2 Function unsigned long to[underscore]ulong() const
  133.  
  134. Description
  135.  
  136. Converts the n least significant bits of *this (where n ==
  137. sizeof(unsigned long) *CHAR[underscore]BIT) to an unsigned long.
  138.  
  139. Exceptions
  140.  
  141. Throws overflow if N > n and any of the bits above position n-1 are set.
  142.  
  143. 3.3 Function string to[underscore]string() const
  144.  
  145. Description
  146.  
  147. Creates a string of 1s and 0s representing the contents of *this. As with
  148. unsigned integers, treats the last character as bit 0.
  149.  
  150. Returns
  151.  
  152. The temporary string of 1s and 0s.
  153.  
  154. 3.4 Function bits<N>& operator=(const bits<N>& b)
  155.  
  156. Description
  157.  
  158. Standard assignment operator.
  159.  
  160. Returns
  161.  
  162. A reference to *this.
  163.  
  164. 3.5 Function int operator== (const bits<N>& b) const
  165.  
  166. Description
  167.  
  168. Compares *this to b for equality. Two bitsets are equal if and only if
  169. their bit patterns are identical.
  170.  
  171. Returns
  172.  
  173. Non-zero if the bitsets are equal, zero otherwise.
  174.  
  175. 3.6 Function int operator!= (const bits<N>& b) const
  176.  
  177. Descrption
  178.  
  179. Compares *this to b for inequality. Equivalent to !operator==().
  180.  
  181. Returns
  182.  
  183. Zero if the bitsets are equal, non-zero otherwise.
  184.  
  185. 3.7 Function set
  186.  
  187. Synopsis
  188.  
  189. bits<N>& set(size[underscore]t, n, int val = 1) bits<N>& set()
  190.  
  191. Description
  192.  
  193. These function set one or more bits. The function set (size[underscore]t,
  194. int) can reset a bit, depending on val.
  195.  
  196. 3.7.1 Function bits<N>& set(size[underscore]t n, int val)
  197.  
  198. Description
  199.  
  200. Sets the nth bit if val is non-zero, otherwise resets the bit.
  201.  
  202. Returns
  203.  
  204. A reference to *this.
  205.  
  206. Exceptions
  207.  
  208. Throws out[underscore]of[underscore]range if n is not in [0,n-1].
  209.  
  210. 3.7.2 Function bits<N>& set()
  211.  
  212. Description
  213.  
  214. Sets all bits.
  215.  
  216. Returns
  217.  
  218. A reference to *this.
  219.  
  220. 3.8 Functions reset
  221.  
  222. Synopsis
  223.  
  224. bits<N>& reset(size[underscore]t n) bits<N>& reset()
  225.  
  226. Description
  227.  
  228. These functions reset one or more bits.
  229.  
  230. 3.8.1 Function
  231.  
  232. bits<N>& reset (size[underscore]t n)
  233.  
  234. Description
  235.  
  236. Resets the nth bit.
  237.  
  238. Returns
  239.  
  240. A reference to *this.
  241.  
  242. Exceptions
  243.  
  244. Throws out[underscore]of[underscore]range if n is not in [[unkeyable],
  245. N-1].
  246.  
  247. 3.8.2 Function bits<N>& resent()
  248.  
  249. Description
  250.  
  251. Resents all bits.
  252.  
  253. Returns
  254.  
  255. A reference to *this.
  256.  
  257. 3.9 Functions toggle
  258.  
  259. Synopsis
  260.  
  261. bits<N>& toggle(size[underscore]t n) bits<N>& toggle()
  262.  
  263. Description
  264.  
  265. These functions toggle one or more bits.
  266.  
  267. 3.9.1 Function bits <N>& toggle(size[underscore]t n)
  268.  
  269. Description
  270.  
  271. Toggles the nth bit.
  272.  
  273. Returns
  274.  
  275. A reference to *this.
  276.  
  277. Exceptions
  278.  
  279. Throws out[underscore]of[underscore]range if n is not in [[unkeyable],
  280. N-1].
  281.  
  282. 3.9.2 Function bits<N>& toggle()
  283.  
  284. Description
  285.  
  286. Toggles all bits.
  287.  
  288. Returns
  289.  
  290. A reference to *this.
  291.  
  292. 3.10 Function bits operator~() const
  293.  
  294. Description
  295.  
  296. Toggles all the bits of a copy of *this.
  297.  
  298. Returns
  299.  
  300. A toggled copy of *this.
  301.  
  302. 3.11 Function int test(size[underscore]t n) const
  303.  
  304. Description
  305.  
  306. Tests if bit n is set.
  307.  
  308. Returns
  309.  
  310. Non-zero if the bit is set, zero otherwise.
  311.  
  312. Exceptions
  313.  
  314. Throws out[underscore]of[underscore]range if n is not in [[underscore],
  315. N-1].
  316.  
  317. 3.12 Function int any() const
  318.  
  319. Description
  320.  
  321. Tests if any bits at all are set.
  322.  
  323. Returns
  324.  
  325. [unkeyable] if all bits are [unkeyable], non-zero otherwise.
  326.  
  327. 3.13 Function int none() const
  328.  
  329. Description
  330.  
  331. Tests if no bits at all are set.
  332.  
  333. Returns
  334.  
  335. None-zero if all bits are [unkeyable], [unkeyable] otherwise.
  336.  
  337. 3.14 Function bits<N>& operator&= (const bits<N>& b)
  338.  
  339. Description
  340.  
  341. Performs a destructive bitwise-AND of b into *this.
  342.  
  343. Returns
  344.  
  345. A reference to *this.
  346.  
  347. 3.15 Function bits<N>& operator/=(const bits<N>& b)
  348.  
  349. Description
  350.  
  351. Performs a destructive bitwise-OR of b into *this.
  352.  
  353. Returns
  354.  
  355. A reference to *this.
  356.  
  357. 3.16 Function bits<N>& operator[unkeyable]=(const bits<N> & b)
  358.  
  359. Description
  360.  
  361. Performs a destructive bitwise exclusive-OR of b into * this.
  362.  
  363. Returns
  364.  
  365. A refernece to *this.
  366.  
  367. 3.17 Function bits<N>& operator>>=(size[unkeyable]t n)
  368.  
  369. Description
  370.  
  371. Shifts *this right destructively (i.e., in place) by n bit positions.
  372. Resets all bits if n > N. To shift "right" by n means that bit 0 receives
  373. the value of bit n, bit 1 receives bit (n+1), etc.
  374.  
  375. Returns
  376.  
  377. A refernce to *this.
  378.  
  379. 3.18 Function bits <N>& operator<<=(size[underscore]t n)
  380.  
  381. Description
  382.  
  383. Shifts *this left destructively by n bit positions. Resets all bits if n
  384. [greater than] N. To shift "left" by n means that bit n receives the
  385. value of bit 0, bit (n+1) receives bit 1, etc.
  386.  
  387. Returns
  388.  
  389. A reference to *this
  390.  
  391. 3.19 Function bits<N> operator [much greater than] (size[underscore]t n)
  392. const
  393.  
  394. Description
  395.  
  396. a non-destrucive version of opertaor [much greater than] = ().
  397.  
  398. Returns
  399.  
  400. The results of the shift in a temporary bits object.
  401.  
  402. 3.20 Function bits<N> operator [much less than] (size[underscore]t n)
  403. const
  404.  
  405. Description
  406.  
  407. a non-destrucive version of operator [much less than] = ().
  408.  
  409. Returns
  410.  
  411. The results of the shift in a temporary bits object.
  412.  
  413. 3.21 Function size[underscore] count (1) const
  414.  
  415. Description
  416.  
  417. Counts the number of bits that are set.
  418.  
  419. Returns
  420.  
  421. The number of 1 bits in *this
  422.  
  423. 3.22 Function size[undrescore] lenght() const
  424.  
  425. Description
  426.  
  427. Returns the fixed-size length of the object.
  428.  
  429. Returns
  430.  
  431. N.
  432.  
  433. 4.0 Global Functions
  434.  
  435. 4.1 Function ostrem& operator[much less than](ostream& os, const bits <N
  436. >& b)
  437.  
  438. Description
  439.  
  440. Sends a sequence of N 1s and 0s corresponding to the bit pattern of *this
  441. to the stream os.
  442.  
  443. Returns
  444.  
  445. A reference to the stream os. 4.2 Function istream& operator>>(istream&
  446. is, bits<N>& b)
  447.  
  448. Description
  449.  
  450. Reads a sequence of up to N 1s and [unkeyable&s from the stream is, after
  451. skipping whitespace. The first non-bit character thereafter terminates
  452. the read and remains in the stream. The corresponding bit pattern is
  453. reproduced in b. Treats the last 1 or [unkeyable] read from the stream as
  454. bit [unkeyable] of b.
  455.  
  456. Returns
  457.  
  458. A reference to the stream is.
  459.  
  460. 4.3 Function bits<N>operator& (const bits<N>& b1, const bits<N>& b2)
  461.  
  462. Description
  463.  
  464. Performs a bitwise-AND of b1 and b.
  465.  
  466. Returns results of the bitwise-AND in a temporary bits object.
  467.  
  468. 4.4 Function bits<N>operator| (const bits<N>& b1, const bits<N>& b2)
  469.  
  470. Description
  471.  
  472. Performs a bitwise-OR of b1 and b.
  473.  
  474. Returns
  475.  
  476. The results of the exclusive-OR in a temporary bits object.
  477.  
  478. Design Notes
  479.  
  480. Having an expression instead of a type as a template parameter hasa the
  481. following effects:
  482.  
  483. * A bits-object can be stack-based, since its size is known at compile
  484. time. This means less run-time overhead and therefore better perforamance
  485. than bitstring objects.
  486.  
  487. * Objects of different sizes (i.e., with a different number of bits) are
  488. different types, and therefore can't be combined in operations.
  489.  
  490. * No global functions taking bits arguments are allowed under the current
  491. definition of the language unless you define them inline in the class
  492. definition. The standards committee is working to fix this. See the
  493. sidebar, "Templates in a Nutshell," for more detail. Since a bits object
  494. is an extension of unsigned integers as far as bitwise operations are
  495. concerned, a collection of bits behaves like a number, in that bit 0 is
  496. the right-most bit. To be consistent with C bitwise operations, the
  497. statements
  498.  
  499. bits<8> b; b |= 5; cout << b << end; give the result
  500.  
  501. 0000101
  502.  
  503. that is, the bits of 5 are ORed with b (via the construcor bits(un-signed
  504. long)).
  505.  
  506. As you can see in Listing 7, I've taken some liberties in the
  507. implementation of this class by changing the type of the template
  508. parameter to a size[underscore]t. The reason for originally making the
  509. number of bits an unsigned long was to guarantee a minimum size across
  510. platforms (the ANSI C standard states that an unsigned long must be at
  511. least 32 bits wide). However, this would require that countt and length
  512. return an unsigned long. As proof that this is unnatural, I offer the
  513. fact that I forgot to do so (the functions return a size[underscore]t
  514. because it "feels right") and no one on the committee noticed. (Actually,
  515. Bill Plauger finally noticed while he was editing the standard library
  516. documents, but that was four months after the bits class became
  517. official.) Furthermore, the corresponding functions in the string and
  518. bitstring classes also return a size[underscore]t. (They have no choice.)
  519. To be consistent with these classes, therefore, and because it just makes
  520. sense, I shall propose to the committee that we approve to obvious and
  521. make the template parameter a size[underscore]t.
  522.  
  523. I'm also thinking of changing the name from bits to bitset. This would
  524. allow you to refer to an object as a "bitset" instead of always having to
  525. say a "bits object." (Who would ever call it a "bits"?) And one could
  526. argue that the function to[underscore]ushort() is superfluous, since it
  527. is equivalent to (unsigned short) to[underscore]ulong().
  528.  
  529. Implementation Notes
  530.  
  531. The Code Capsuel "Bit Handling in C" (CUJ, November, 1993) provides a
  532. thorough explanation of the internals of using an integral array to store
  533. and access individual bits, so I won't repeat it here. The techniques
  534. found therein serve both the bitstring and bits classes. The
  535. implementation of the string class is in last month's installment ("Bit
  536. Handling in C++, Part 1," CUJ, December functions of the bits class.
  537.  
  538. Sets of Integers
  539.  
  540. For those of you who miss some of the high-level features of Pascal and
  541. Modula-2, the bits class gives you sets of integers almost for free. Just
  542. define a bits object of a size appropriate for your application and do
  543. the following:
  544.  
  545. For the set operations:
  546.  
  547. insert x into s remove x from s x member of s? complement of s s1 + s21
  548. (union) s1 * s2 (intersection) s1 - s2 (diffrence) s1 <= s2 (subset) s1
  549. >= s2 (superset)
  550.  
  551. Do this:
  552.  
  553. s.set(x) s.reset(x) s.test(x) s.toggle() or [unkeyable]s s1 | s2 s2 & s2
  554. see below see below see below
  555.  
  556. If this still seems too "low-level," it is a trivial matter to define a
  557. set-like interface to the bits class. Listing 9 defines a class template
  558. called Intset that has all the basic set operations along with an ostream
  559. inserter. The only operations that take any thought at all (but only very
  560. little) are set difference and subset. To remove from s1 the elements of
  561. s2, just reset in s1 the bits that are set in s2:
  562.  
  563. s1.bitset &= [unkeyable]s2.bitset; // see Intset<N>::operator-
  564.  
  565. If s1 is a subset of s2, then s1 is nothing more nor less than the
  566. intersection of the two sets:
  567.  
  568. s1- == s1 & s2 // true iff s1 <= s2
  569.  
  570. The test program in Listing 10 shows how to use the Intset class.
  571.  
  572. Conclusion
  573.  
  574. The acceptance of these two bit handling classes by the C++ standards
  575. committee shows that the needs of the sytem programmer have not been
  576. forgotten. Much of the hullabaloo over object-oriented technology
  577. emphasizes inheritance hierarchies of polymorphic, high-level abstract
  578. data types. These concepts are best left to specialized libraries and
  579. applications while the standard rightly focuses on commonly needed,
  580. low-level abstractions. If you have any comments on these classes, please
  581. contact me at the email address in the by-lin at the bottom of the page
  582. of this article.
  583.  
  584. Listing 1 A function template for swapping two objects for the same type
  585.  
  586. // swap.cpp #include <iostream.h>
  587.  
  588. template<class T> void swap(T& x, T& y) { T temp = x; x = y; y = temp; }
  589.  
  590. main() { int a = 1, b = 2; double c = 1.1, d = 2.2; char *s = "hello', *t
  591. = "there"; swap(a,b); cout [much less than] "a = " [much less than] a
  592. [much less than]", b [much less than] b [much less than] '[unkeyable]n';
  593. swap(c,d); cout [much less than] "c = " [much less than] c [much less
  594. than]", d = " [much less than] d [much less than] '[unkeyable]n';
  595. swap(s,t); cout [much less than] "s = "[much less than]", t = " [much
  596. less than] t [much less than] '[unkeyable]n'; return 0; } /* Output: a =
  597. 2, b = 1 c = 2.2, d = 1.1 s = there, t = hello
  598.  
  599. // End of File
  600.  
  601. Listing 2 A class for a stack of integers
  602.  
  603. // stackl.h; A C++ integer stack class #include <stddef.h>
  604.  
  605. class Stack { size[underscore]size; int *data; int ptr;
  606.  
  607. public: stack(size[underscore]t); ~Stack(); void push(nt); int pop(); int
  608. empty() const; int full() const; };
  609.  
  610. inline Stack::Stack(size[underscore] siz) { data = new int[size = siz];
  611. ptr = 0; }
  612.  
  613. inline Stack::~Stack() { delete [] data; }
  614.  
  615. inline int Stack::empty() const { return ptr = = 0; }
  616.  
  617. inline int Stack::full() const { return ptr = = size; }
  618.  
  619. // End of File
  620.  
  621. Listing 3 Out-of-line functions for the stack class
  622.  
  623. // stackl.cpp #include "stack1.h"
  624.  
  625. void Stack::push(int x) { if (ptr [less than] size) data[ptr++] = x; }
  626.  
  627. int Stack::pop() { if (ptr [greater than] 0) --ptr; return data[ptr]; }
  628.  
  629. // End of File
  630.  
  631. Listing 4 A class template for homogeneous stacks
  632.  
  633. // stack2.h: A C++ stack class template #include <stddef.h>
  634.  
  635. template<class T> class Stack { size[underscore]t size; T *data; int ptr;
  636.  
  637. public: Stack(size[underscore]t); ~stack(); void push(const T&); T pop();
  638. int empty() const; int full() const; };
  639.  
  640. template<class T> inline Stack<T>::Stack(size[underscore]t siz) { data =
  641. new T[size = siz]; ptr = 0; }
  642.  
  643. template<class T> inline Stack<T>::~Stack() { delete [] data; }
  644.  
  645. template<class T> void Stack<T>:;push(const T& x) { if (ptr [less than]
  646. size) data[ptr++] = x; }
  647.  
  648. template<class T> T Stack<T>::pop() { if (ptr [greater than] 0) --ptr;
  649. return data[ptr]; }
  650.  
  651. template<class T> inline int Stack<T>::empty() const { return ptr = = 0;
  652. }
  653.  
  654. template<class T> inline int Stack<T>::full() const { return ptr = =
  655. size; }
  656.  
  657. // End of File
  658.  
  659. Listing 5 Illustrates the stack template class
  660.  
  661. // tstack2.h #include <lostream.h> #include "stack2.h"
  662.  
  663. main() { Stack<int> s1(5), s2(5); // Push odds onto s1, evens onto s2:
  664. for (int i = 1; i [less than] 10; i += 2) { s1.push(i); s2.push(i+1); }
  665.  
  666. // Retrieve and print in LIFO order: cout [much less than] "Stack 1:
  667. [unkeyable]n"; while (!s1.empty()) cout [much less than] s1.pop() [much
  668. less than] end1;
  669.  
  670. cout [much less than] "Stack 2:[unkeyable]n"; while (!s2.empty()) count
  671. [much less than] s2.pop() [much less than] end1; return 0; }
  672.  
  673. /* Output: Stack 1: 9 7 5 3 1 Stack 2: 10 8 6 4 2 */
  674.  
  675. /* End of File */
  676.  
  677. Listing 6 The bits class template interface
  678.  
  679. template<unsinged long N> class bits {
  680.  
  681. // Friends: // Global I/0 functions frined ostream& operator<<(ostream&,
  682. const bits<N>&); friend istream& operator>>(istream&, bits<N>&);
  683.  
  684. /// Global bitwise operators friend bits<N> operator&(const bits<N>&,
  685. const bits<N>&); friend bits<N> operator|(const bits<N>&, const bits<N
  686. >&); friend bits<N> operato[unkeyable](const bits<N>&, const bits<N>&);
  687.  
  688. public: // Constructors bits(); bits(unsigned long n); bits(const bits<N
  689. >& b); bits(const string& s);
  690.  
  691. // Conversions unsigned short to[underscore]() const; unsigned long to
  692. [underscore]() const; string to[underscore]string() const;
  693.  
  694. // Assignment bits<N>& operator=(const bits<N>& rhs);
  695.  
  696. // Equality int operator==(const bits<N>& rhs) const; int
  697. operator!"(const bits<N>& rhs) const;
  698.  
  699. // Basic bit operations bits<N>& set(size[underscore]t pos, int val = 1);
  700. bits<N>& set(); bits<N>& reset(size[undrescore]t pos); bits<N>& reset();
  701. bits<N>& toggle(size[underscore]t pos); bits<N>& toggle(); bits<N>
  702. operator~() const; int test(size[underscore]t n) const; int any() const;
  703. int none() const;
  704.  
  705. // Bit-wise operators bits<N>& operator&= (const bits <N>& rhs); bits<N>&
  706. operator|=(const bits<N>& rhs); bits<N>& operator[unkeyable]=(const bits
  707. <N>& rhs);
  708.  
  709. // Shift operators bits<N>& operator <<=(size[unkeyable]t n); bits<N>&
  710. operator >>=(size[unkeyable]t n); bits<N>& operator <<=(size[unkeyable]t
  711. n); const; bits<N>& operator >>=(size[unkeyable]t n); const;
  712.  
  713. size[underscore]t count() const; size[underscore]t length() const;
  714.  
  715. };
  716.  
  717. // End of File
  718.  
  719. Listing 7 An implementation of the bits class template
  720.  
  721. // bits.h
  722.  
  723. #include <iostream.h> #include <stddef.h> #include <limits.h> #include
  724. <asset.h> #include "string.hpp"
  725.  
  726. template<size[unkeyalbe]t N> class bits {
  727.  
  728. // Global I/0 functions friend ostream& operator<<(ostream& os, const
  729. bits<N>& rhs) {os << rhs.to[unkeyable]string(); return os;} friend
  730. istream& operator>>(istream& is, bits<N>& rhs) {rhs.read(is); return is;}
  731.  
  732. // Global bitwise operators frined bits<N> operator&(const bits<N>& b2)
  733. {bits<N> r(bl); return r &= b2;} friend bits<N> operator|(const bits<N>&
  734. b1, const bits<N>& b2) {bits<N> r(b1); return r |= b2;} friend bits<N>
  735. operator[unkeyable](const bits<N>& b1, const bits <N>& b2) {bits<N>
  736. r(bl); return r [unkeyable]= b2;}
  737.  
  738. public: // Constructors bits(); bits(unsigned long n); bits(const bits<N
  739. >& b); bits(const string& s);
  740.  
  741. // Conversions unsigned short to[unkeyable]unshort() const; unsinged long
  742. to[underscore]ulong() const; string to[underscore]() const;
  743.  
  744. // Assignment bits<N>& operator=(const bits <N>& rhs);
  745.  
  746. // Equality int operator==(const bits <N>& rhs) const; int
  747. operator!=(const bits <N>& rhs) const;
  748.  
  749. // Basic bit operations bits<N>& set(size[unkeyable]t pos, int val = 1);
  750. bits<N>& set(); bits<N>& reset(size[unkeyable]t pos); bits<N>& reset();
  751. bits<N>& toggle(size[unkeyable]t pos); bits<N>& toggle(); bits<N>
  752. operator~() const; int test(size[unkeyable]t n) const; int any() const;
  753. int none() const;
  754.  
  755. // Bit-wise operators bits<N>& operator&=(const bits<N>& rhs); bits<N>&
  756. operator|=(const bits<N>& rhs); bits<N>& operator[unkeyable]=(const bits
  757. <N>& rhs);
  758.  
  759. // Shift operators bits<N>& operator<<=(size[unkeyable]t n); bits<N>&
  760. operator>>=(size[unkeyable]t n); bits<N>& operator<<=(size[unkeyable]t n)
  761. const; bits<N>& operator>>=(size[unkeyable]t n) const;
  762.  
  763. size[unkeyable]t count() const; site[unkeyable] lenght() const;
  764.  
  765. private: typedef unsinged int Block; enum {BLKSIZ = CHAR[unkeyable]BIT *
  766. sizeof (Block)}; enum {nblks[unkeyable]=(N+BLSKSIZ-1) / BLKSIZ};
  767.  
  768. Block bits[unkeyalbe][nblks];
  769.  
  770. static size[unkeyable]t word(size]unkeyable] pos) {return nblks[unkeyable
  771. ] - 1 - pos/BLKSIZ;} static size[unkeyable]t offset(size[unkeyable]t pos)
  772. {return pos % BLKSIZ;} static Block mask1(size[unkeyable]t pos) {return
  773. Block(1) << offset(pos);} static Block mask0(size[unkeyable]t pos)
  774. {return ~(Block(1) << offse(pos));}
  775.  
  776. void cleanup(); void set[unkeyable](size[unkeyable]t pos); int set
  777. [unkeyable]t pos, int val); void reset[unkeyable](size[unkeyable]t pos);
  778. int test[unkeyable](size[unkeyable]t pos) const; void from[unkeyable
  779. ]string (const string& s); void read(istream& is); int any(size[unkeyable
  780. ]t start[unkeyable]pos) const; unsigned lont to(size[unkeyable]t) const;
  781. };
  782.  
  783. template<size[unkeyable]t N> inline bits<N>::bits() { template<size
  784. [unkeyable]t N> string bits<N>::to[unkeyable]string() const {
  785.  
  786. char *s = new char[N+1]; for (int i = 0; i < N; ++i) s[i] = '0' + test
  787. [unkeyable](N-1-i); s[N] = '/0'; string s2(s); delete [] s; return s2; }
  788.  
  789. template<size[unkeyable]t N> bits<N>& bits<N>::operator=(const bits<N>&
  790. b) } if (this != &b) memcyp(bits[unkeyable],b.bits[unkeyable], nblks
  791. [unkeyable] * sizeof(bit[unkeyable][0])); return *this; }
  792.  
  793. template<size[unkeyable]t N> inline int bits<N>::operator==(const bits<N
  794. >& b) const } return !memcmp(bit[unkeyable],bit[unkeyable],nblks
  795. [unkeyable] * sizeof(bits[unkeyable][0])); }
  796.  
  797. template<size[unkeyable]t N> inline int bits<N>::operator!=(const bits<N
  798. >& b) const } return !operator==(b); } template<size[unkeyable]t N>
  799. inline bits<N>& bits<N>::set(size[unkeyable]t pos, int val0 }
  800.  
  801. assert(pos < N); (void) set[unkeyable](pos, val); return *this; }
  802.  
  803. template<size[unkeyable]t N> inline bits<N>& bits<N>::set() } memset(bits
  804. [unekyable],~0u,nblks[unkeyable] * sizeof bits[unkeyable][0]); cleanup();
  805. return *this; }
  806.  
  807. template(size[unkeyable]t N inline bits<N>& bits<N>::reset(size[unkeyable
  808. ]t pos) { assert(pos < N); reset[unkeyable](pos); return *this; }
  809.  
  810. template<size[unkeyable]t N> inline bits<N>& bits<N>::reset() }
  811. memset(its[unkeyble],0,nblks[unkeyable] * sizeof bits[unkeyable][0]);
  812. return *this; }
  813.  
  814. template<size[unkeyable]t N> inline bits<N>& bits<N>::toggle(size
  815. [unkeyable]t pos) } asser(pos < N); bits[unkeyable][Word(pos)] [unkeyable
  816. ]= mask1(pos); return *this; } for (int i = 0; i < nblks[underscore];
  817. ++i)
  818.  
  819. bits[underscore][i] [unkeyable]= rhs.bits[underscore][i];
  820.  
  821. return *this; } tremplate<size[underscore]t N> bits<N>& bits<N>::operator
  822. >>=(size[underscore]t n) }
  823.  
  824. if (n > N)
  825.  
  826. n = N;
  827.  
  828. for (int i = 0; i < N-n; ++i)
  829.  
  830. (void) set[underscore](i,test[underscore](i+n));
  831.  
  832. for (i = N-n; i < N; ++i)
  833.  
  834. reset[underscore](i);
  835.  
  836. return *this; } template<size[underscore]t N> bits<N>& bits<N>::operator<
  837. <=(size[underscore]t n) }
  838.  
  839. if (n > N)
  840.  
  841. n = N;
  842.  
  843. for 9int i = N-1, i >= n; --i)
  844.  
  845. (void) set[underscore](i,test(i-n));
  846.  
  847. for (i = 0; i < n; ++i)
  848.  
  849. reset[underscore](i);
  850.  
  851. return *this; }
  852.  
  853. template<size[underscore]t N> inline bits<N> bits<N>::operator>>(size
  854. [underscore]t n) const }
  855.  
  856. bits r(*this);
  857.  
  858. return r >>= n; }
  859.  
  860. template<size[underscore]t N> inline bits<N>::operator<<(size[underscore
  861. ]t n) const }
  862.  
  863. bits r(*this);
  864.  
  865. return r <<= n; }
  866.  
  867. template<size[underscore]t N> size[underscore]t bits<N>::count() const }
  868.  
  869. size[underscore]t sum = 0;
  870.  
  871. for (int i = 0; i < N; ++i)
  872.  
  873. if (test[underscore](i))
  874.  
  875. ++sum;
  876.  
  877. return sum; }
  878.  
  879. template<size[underscore]t N> inline size[underscore]t bits<N>::length()
  880. const }
  881.  
  882. return N; }
  883.  
  884. // Private functions template<size[underscore]t N> inline void bits<N
  885. >::set[underscore](size[underscore]t pos) }
  886.  
  887. bits [word(pos)] |=mask1 (pos); }
  888.  
  889. template<size[underscore]t N> int bits<N>::set[underscore](size
  890. [underscore]t pos, int val) }
  891.  
  892. if (val) template<size[underscore]t N> bits<N>& bits<N>::toggle() }
  893.  
  894. size[underscore]t nw = nblks[underscore];
  895.  
  896. while (nw--)
  897.  
  898. bits[underscore][nw] = [unkeyable]bits[underscore][nw];
  899.  
  900. cleanup();
  901.  
  902. return *this; }
  903.  
  904. template<size[underscore]t N> inline bits<N> bits <N> bits <N>::operator
  905. [unkeyable]() const }
  906.  
  907. bits<N> b(*this);
  908.  
  909. b.toggle();
  910.  
  911. return b; }
  912.  
  913. template<size[underscore]t N> inline int bits <N>::test(size[underscore]t
  914. pos) const }
  915.  
  916. assert (pos < N);
  917.  
  918. return test[underscore](pos); }
  919.  
  920. template<size[underscore]t N> int bits <N>::any() const }
  921.  
  922. for (int i = 0; i < nblks[underscore]; ++i)
  923.  
  924. if (bits[underscore][i])
  925.  
  926. return 1:
  927.  
  928. return 0; }
  929.  
  930. template<size[underscore]t N> inline int bits<N>::none() const }
  931.  
  932. return !any(); }
  933.  
  934. template<size[unkeyable]t N> bits<N>& bits<N>::operator&=(const bits<N>&
  935. rhs) }
  936.  
  937. for (int i = 0; i < nblks[underscore]; ++i)
  938.  
  939. bits[underscore][i] &= rhs.bits[underscore][i];
  940.  
  941. return *this; }
  942.  
  943. template<size[underscore]t N> bits<N>& bits <N>::operator|=(const bits<N
  944. >& rhs) }
  945.  
  946. for (int i = 0; i < nblks[unkeyable]; ++i)
  947.  
  948. bits[unkeyable][i] |= rhs.bits[unkeyable][i];
  949.  
  950. return *this; }
  951.  
  952. template<size[underscore]t N> bits <N>& bits <N>::operator[unkeyable
  953. ]=(const bits<N>& rhs) }
  954.  
  955. set[underscore](pos);
  956.  
  957. else
  958.  
  959. reset[underscore](pos);
  960.  
  961. return !!val; }
  962.  
  963. template<size[underscore]t N> inline void bits<N>::reset[underscore]t
  964. pos) }
  965.  
  966. bits[underscore][word(pos)] &= mask0(pos); }
  967.  
  968. return !!(bits[underscore][word(pos)] & mask1(pos)); }
  969.  
  970. template<size[underscore]t N> inline void bits<N>::cleanup() }
  971.  
  972. // Make sure unused bits don't get set
  973.  
  974. bits[underscore][0] &= ([unkeyable]Block(0) >> (nblks[underscore] *
  975. BLKSIZ - N)); }
  976.  
  977. template<size[underscore]t N> void bits <N>::from[underscore]string(const
  978. string& s) }
  979.  
  980. // Assumes s contains only 0's and 1's
  981.  
  982. size[underscore]t slen = s.length();
  983.  
  984. reset();
  985.  
  986. for (int i = slen-1; i >= 0; --i)
  987.  
  988. if (s.get[underscore]at(i) == '1')set[underscore](slen-i-1); }
  989.  
  990. template<size[underscore]t N> void bits<N>::read(istream& is) }
  991.  
  992. char *buf = new char[N]; char c;
  993.  
  994. is >> ws; for (int i = 0; i < N; ++i) } is. get(c); if (c == '0' || c ==
  995. '1') buf[i] = c; else } is.putback(c); buf[i] = '/0'; break; } }
  996.  
  997. if (i == 0) is. clear(ios::failbit); else from[underscore
  998. ]string(string(buf)); delete buf; }
  999.  
  1000. template<size[underscore]t N> int bits<N>::any(size[underscore]t start)
  1001. const { // See if any bit past start (inclusive) is set
  1002.  
  1003. for (int i = start; i < N;   i)
  1004.  
  1005. if (test[underscore](i)) return 1; return 0; }
  1006.  
  1007. template<size[underscore]t N) unsigned long bits<N>:: to size[underscore
  1008. ]t nblks) const { if (nblks > 1) { int i; unsigned long n = bits
  1009. [underscore][nblks[underscore] - nblks];
  1010.  
  1011. /* Collect low-order sub-blocks into an unsigned */ if (nblks > nblks)
  1012. nblks = nblks[underscore]; while ( - -nblks) n = (n << BLKSIZ) | bits
  1013. [underscore][nblks[underscore] - nblks]; return n; } else return
  1014. (unsigned long) bits[underscore][nblks[underscore] - 1 ]; }
  1015.  
  1016. /* End of File */
  1017.  
  1018. Listing 8 Tests the bits class
  1019.  
  1020. // tbits.cpp #include <iostream.h> #include <iomanip.h> #include
  1021. <stddef.h> #include <limits.h> #include "bits.h"
  1022.  
  1023. main() { const sizetunderscore]t SIZE = CHAR[underscore]BIT *
  1024. sizeof(unsigned long); unsigned long n = 0x12345678; bits<SIZE> x(n),
  1025. y(string("10110")), z(x);
  1026.  
  1027. cout << "Initial x: " << x << endl; cout << "Initial y: " << y << endl;
  1028. cout << "Initial z: " << z << endl; cout << "Enter new z: "; cin >> z;
  1029. cout << "New z: " << z << endl; cout << "z == " << z.to[underscore
  1030. ]ulong() << endl; cout << "y == " << y.to[underscore]ushort() << endl;
  1031. cout << "x == " << x.to[underscore]ulong() << endl;
  1032.  
  1033. cout << "x: " << x << " (" << x.count() << " bits set)" << endl; cout <<
  1034. "x == 0x12345678L? " << (x == 0x12345678L) << endl; cout << "x: " << x <<
  1035. endl; cout << "x: " << hex << setfill('0') << setw(sizeof(unsigned
  1036. long)*2) << x. to[underscore]ulong() << dec << endl; cout << "x <<= 6 ==
  1037. " << (x <<= 6) << endl; cout << "x >>= 6 == " << (x >>= 6) << endl; cout
  1038. << "85 == " << bits<SIZE>(85) << endl; cout << "x [unkeyable] 85 == " <<
  1039. (x [unkeyable] 85) << endl; cout << "x & 85 == " << (x & 85) << endl;
  1040. cout << "85 & x === " << (85 & x) << endl; cout << "[unkeyable]x == " <<
  1041. ([unkeyable]x) << " == " << ([unkeyable]x).to[underscore]ulong() << endl;
  1042.  
  1043. y = 0x55555550L; cout << "y: " << y << " (" << y.count() << " bits set)"
  1044. << endl; cout << "y[0]: " << hex << setfill ('0') << setw(sizeof(unsigned
  1045. long)*2) << y.to[underscore]ulong() << dec << endl; cout << "x 8 y == " <
  1046. < (x 8 y) << endl; cout << "x | y == " << (x | y) << endl; cout << "x
  1047. [unkeyable] y == " << (x [unkeyable] y) << endl; cout << "x != y? " << (x
  1048. != y) << endl; return 0; }
  1049.  
  1050. /* Sample Execution: Initial x: 00010010001101000101011001111000 Initial
  1051. y: 00000000000000000000000000010110 Initial z:
  1052. 00010010001101000101011001111000 Enter new z: 101001000100001000001 New
  1053. z: 00000000000101001000100001000001 z == 1345601 y == 22 x == 305419896
  1054. x: 00010010001101000101011001111000 (13 bits set) x == 0x12345678L? 1 x:
  1055. 00010010001101000101011001111000 x: 12345678 x <<= 6 ==
  1056. 10001101000101011001111000000000 x >>= 6 ==
  1057. 00000010001101000101011001111000 85 == 00000000000000000000000001010101 x
  1058. [unkeyable] 85 == 000000100011010001101000101011000101101 x & 85 ==
  1059. 000000000000000000000000001010000 85 & x ===
  1060. 00000000000000000000000001010000 [unkeyable]x ==
  1061. 11111101110010111010100110000111 == 4257982855 y:
  1062. 0101010101010101010101010101010000 (14 bits set) y[0]: 55555550 x & y ==
  1063. 00000000000101000101010001010000 x | y ==
  1064. 0101011101110101010101011101111000 x [unkeyable] y ==
  1065. 01010111011000010000001100101000 x != y? 1
  1066.  
  1067. // End of File
  1068.  
  1069. Listing 9 Implementation of sets of integers
  1070.  
  1071. #if !defined(INTSET[underscore]H) #define INTSET[underscore]H
  1072.  
  1073. #include <iostream.h> #include <stddef.h> #include "bits.h"
  1074.  
  1075. template<size[underscore]t N> class Intset {
  1076.  
  1077. public:
  1078.  
  1079. // NOTE: The following constructors shouldn't be // necessary. The
  1080. compiler-generated ones should // suffice. For some reason, Borland 3.1
  1081. requires // these (WATCOM does not).
  1082.  
  1083. // Constructors Intset(); Intset(const Intset<N>& is);
  1084.  
  1085. // set operations Intset<N> operator-(const Inset<N>& is) const; Intset<N
  1086. > operator (const Intset<N>& is) const; Intset<N> operator*(const Intset
  1087. <N>& is) const; Intset<N> operator[unkeyable]() const; int
  1088. operator==(const Inset<N>& is) const; int operator!=(const Entset<N>& is)
  1089. const; int operator<=(const Intset<N>& is) const; int operator>=(const
  1090. Intset<N>& is) const;
  1091.  
  1092. //Member operations int contains(size[underscore]t n) const; Intset<N>&
  1093. insert(size[underscore]t n); Intset<N>& remove(size[underscore]t n);
  1094.  
  1095. size[underscore]t count() const; friend ostream& operator<<(ostream& os,
  1096. const Intset<N>& is) {is.print(os); return os;}
  1097.  
  1098. private:
  1099.  
  1100. bits<N> bitset;
  1101.  
  1102. int subsetof(const Intset<N>& is) const; void print(ostream& os) const;
  1103. };
  1104.  
  1105. template<size[underscore]t N> Intset<N>::Intset() {
  1106.  
  1107. bitset.reset(); }
  1108.  
  1109. template<size[underscore]t N> Intset<N>::Intset(const Intset<N>& is) {
  1110. bitset = is.bitset; }
  1111.  
  1112. template<size[underscore]t N> inline Intset<N> Intset<N>::operator-(const
  1113. Intset<N> &is) const {
  1114.  
  1115. Intset<N> r(*this); r.bitset &= [tilde]is.bitset; return r; }
  1116.  
  1117. template<size[underscore]t N> inline Intset<N> Intset<N>::operator+(const
  1118. Intset<N> &is) const {
  1119.  
  1120. Intset<N> r(*this); r.bitset |= is.bitset; return r; }
  1121.  
  1122. template<size[underscore]t N> inline Intset<N> Intset<N>::operator*(const
  1123. Intset<N> &is) const {
  1124.  
  1125. Intset<N> r(*this); r.bitset &= is.bitset; return r; }
  1126.  
  1127. template<size[underscore]t N> inline Intset<N> Intset<N>::operator[tilde
  1128. ]() const {
  1129.  
  1130. Intset<N> r(*this); r.bitset.toggle(); return r; }
  1131.  
  1132. template<size[underscore]t N> inline int Intset<N>::operate==(const
  1133. Intset<N> &is) const {
  1134.  
  1135. return bitset == is.bitset; }
  1136.  
  1137. template<size[underscore]t N> inline int Intset<N>::operator!=(const
  1138. Intset<N> &is) const {
  1139.  
  1140. return bitset ! = is.bitset; }
  1141.  
  1142. template<size[underscore]t N> inline int Intset<N>::operator<=(const
  1143. Intset<N> &is) const {
  1144.  
  1145. return subsetof(is); }
  1146.  
  1147. template<size[underscore]t N> inline int Intset<N>::operator>=(const
  1148. Intset<N> &is) const {
  1149.  
  1150. return is.subsetof(*this); }
  1151.  
  1152. template<size[underscore]t N> inline int Intset<N>::contains(size
  1153. [underscore]t n) const {
  1154.  
  1155. return bitset.test(n) }
  1156.  
  1157. template<size[underscore]t N> inline Intset<N>& Intset<N>::insert(size
  1158. [underscore]t N> {
  1159.  
  1160. bitset.set(n); return *this; }
  1161.  
  1162. template<size[underscore]t N> inline Intset<N>& Intset<N>::remove(size
  1163. [underscore]t n) {
  1164.  
  1165. bitset.reset(n); return *this; }
  1166.  
  1167. template<size[underscore]t N> inline size[underscore]t Intset<N>::count()
  1168. const {
  1169.  
  1170. return bitset.count(); }
  1171.  
  1172. template<size[underscore]t N> inline int Intset<N>::subsetof(const Intset
  1173. <N>& is) const {
  1174.  
  1175. bits<N> r(bitset); r &= is.bitset; return bitset == r; }
  1176.  
  1177. template<size[underscore]t N> void Intset<N>::print(ostream& os) const {
  1178.  
  1179. os << '{'; int first[underscore]time = 1; for (int i = 0; i < N; ++i) if
  1180. (bitset.test(i)) {
  1181.  
  1182. if (!first[underscore]time) os << ','; os << i; first[underscore]time =
  1183. 0; }
  1184.  
  1185. os << '}'; }
  1186.  
  1187. #endif
  1188.  
  1189. /* End of File */
  1190.  
  1191. Listing 10 Tests the Intset class
  1192.  
  1193. //tintset.cpp #include <iostream.h> #include "intset.h"
  1194.  
  1195. main() {
  1196.  
  1197. Intset<16> x, y;
  1198.  
  1199. for (int i = 0; i < 10; ++i) {
  1200.  
  1201. x.insert(i); if (i % 2) y.insert(i); }
  1202.  
  1203. cout << "x == " << x << endl; cout << "y == " << y << endl; cout << "y <=
  1204. x? "<< (y <= x) << end; cout << "y >= x? " << (y >= x) << endl; cout <<
  1205. "x - y == " << x - y << endl; cout << "x + y == " << x + y << endl; cout
  1206. << "x * y == " << x * y << endl; cout << "[tilde]x == " << [tilde]x <<
  1207. endl; cout << "x.contains(2)? " << x.contains(2) << endl; cout <<
  1208. "y.contains(2)? " << y.contains(2) << endl; cout << "x.count() == " <<
  1209. x.count() << endl; cout << "y.count() == " << y.count() << endl; return
  1210. 0; }
  1211.  
  1212. /* Output; x == {0,1,2,3,4,5,6,7,8,9} y == {1,3,5,7,9} y <= x? 1 y >= x?
  1213. 0 x - y == {0,2,4,6,8} x + y == {0,1,2,3,4,5,6,7,8,9} x * y == {1,3,5,7,9
  1214. } [tilde]x == {10,11,12,13,14,15} x.contains(2)? 1 y.contains(2)? 0
  1215. x.count() == 10 y.count() == 5 */
  1216.  
  1217. // End of File
  1218.  
  1219. Related article: Templates In A Nutshell
  1220.  
  1221. A template is a parameterized layout for defining a function of class.
  1222. The parameters are usually types, but class templates can also have value
  1223. parameters. Template definitions allow you to specify the logic of a
  1224. function or class once and then have the compiler create specific
  1225. functions or classes for different types as you need them.
  1226.  
  1227. Function Templates
  1228.  
  1229. Consider the swap function
  1230.  
  1231. void swap(int& x, int& y) {
  1232.  
  1233. int temp = x; x = y; temp = y; }
  1234.  
  1235. This works only for integer argumants. You need a different version of
  1236. swap for each data type for which you want to swap elements. If you
  1237. inspect the version for doubles:
  1238.  
  1239. void swap(double& x, double& y) {
  1240.  
  1241. double temp = x; x = y; temp " y; }
  1242.  
  1243. you'll notice that the only change was to substitute double for int in
  1244. the text. This suggests a macro solution, with the data type as a
  1245. parameter:
  1246.  
  1247. // genswap.h #define genswap(T) void swap(T& x, T& y) / } /
  1248.  
  1249. T temp = x; / x = y; / y = temp; / }
  1250.  
  1251. To generate different versions of swap, call genswap as needed:
  1252.  
  1253. #include <iostream.h> #include "genswap.h"
  1254.  
  1255. genswap(int) // Awkward syntax, genswap(double) // I'll admit.
  1256.  
  1257. main() {
  1258.  
  1259. int i = 1, j = 2; double x = 1.1, y = 2.2; swap(i, j); swap(x,y); cout
  1260. [much less than] i [muchless than] ',' [much less than] j [much less than
  1261. ] end1; // 2,1 cout [much less than] x [much less than] ',' [much less
  1262. than] y "much less than] end1, // 2.2,1.1 return 0; }
  1263.  
  1264. This has the advantage of allowing you to specift the function logic only
  1265. once.
  1266.  
  1267. A function template is much the same as the genswap macro, except that
  1268. you don't have to explicitly generate the functions you need. After
  1269. seeing the template defition
  1270.  
  1271. template<class T> void swap(T& x, T& y) {
  1272.  
  1273. T temp = x; x = y; y = temp; }
  1274.  
  1275. the compiler automatically generates versions as needed when it finds a
  1276. call to swap. (See Listing 1.) You can use any type, including built-ins,
  1277. for the template argument.
  1278.  
  1279. Class Templates
  1280.  
  1281. You can also parameterize class definitions. A good candidate is a stack,
  1282. since the logic of stack operations is the same no matter what type the
  1283. stack elements are. Listing 2 and 3 have the definition of an integer
  1284. stack class. To templatize this class, procede the class definition with
  1285. the line
  1286.  
  1287. template<class T>
  1288.  
  1289. as before, and change all occurrences of int that refer to the type of
  1290. elements on the stack to T (see Listing 4). You instantiate a specific
  1291. stack class like this:
  1292.  
  1293. Stack<int> s1(5);
  1294.  
  1295. This type of s1 is Stack<int> ("stack of int"). The token Stack cannot
  1296. appear unqualified outside of the class template definition. See Listing
  1297. 5 for an example of using Stack template classes. (Point of Terminology:
  1298. A "class template" is the original template definition. A "template
  1299. class" is a particular class instantiated from the class template, such
  1300. as Stack<int>.)
  1301.  
  1302. Note that there is no separate stack2.cpp file. My compilers (Borland 3.1
  1303. and WATCOM 9.5) require the entire class implementation to be visible
  1304. during compilation, so everything is in an include file.
  1305.  
  1306. A class template can also have value parameters. The bits class in this
  1307. article is a good example:
  1308.  
  1309. template<size [underscore] t N> class bits {
  1310.  
  1311. // ... };
  1312.  
  1313. The value for N must be a constant expression when instantiated:
  1314.  
  1315. bits<16> b1; // ok const size [underscore] t n = 32; bits<n> b2; // ok
  1316. size [underscore] t m = 64; bits<m> b3; // nope - m not const
  1317.  
  1318. Since the specific values of N in a program are known at compile time,
  1319. the array inside a bits<N> object can be placed on the stack, thus
  1320. avoiding the need for dynamic memory management.
  1321.  
  1322. A disadvantage of value parameters occurs with friend functions. Consider
  1323. the friend function operator& defined in the bits class. To define this
  1324. outside of the class definition itself, you would have to write:
  1325.  
  1326. template<size [underscore] t N> bits<N> operator&(const bits<n>& b1,
  1327. const bits<N>& b2) {
  1328.  
  1329. // ... }
  1330.  
  1331. Since this is not a member function, the compiler recognizes it as a
  1332. function template definition. Under the current definition of the
  1333. language, global function templates can only have type arguments (e.g.,
  1334. class T), because a compiler uses overloading rules to resolve them.
  1335. That's why I had to fully define all friends inside of the bits<N> class
  1336. template definition. The joint C++ standards comittee voted in November
  1337. to allow out-of-line definitions of friend functions for class templates.
  1338. -------------------------------------------------------------------------
  1339. Type:      Tutorial
  1340.            Column
  1341. Topic:     C Programming Language
  1342.            Object-Oriented Programming
  1343.            Program Development Techniques
  1344.            Bit Manipulation
  1345.            Program Libraries
  1346.            Functions
  1347.            Tutorial
  1348.  
  1349.  
  1350. Record#:   15 012 510
  1351.                               *** End ***
  1352.