home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c221 / 1.ddi / DOC / README.CPP < prev    next >
Encoding:
Text File  |  1992-04-21  |  12.8 KB  |  313 lines

  1.        Copyright (C) 1992 MetaWare Incorporated.  All Rights Reserved.
  2.  
  3.                           High C/C++ Version 3.0
  4.                        Globally Optimizing Compiler
  5.                 for Extended DOS 80386/486 and Windows 3.0
  6.                                April 1992
  7.  
  8.                         +------------------------+
  9.                         |  Notes About High C++  |
  10.                         +------------------------+
  11.  
  12.  
  13. Table of Contents
  14. -----------------
  15.  1.  Pointer-to-member comparison
  16.  2.  Using templates
  17.      2.1  Ways to control the single-copy problem
  18.      2.2  Class templates
  19.      2.3  Checking template usage
  20.      2.4  A note on terminology
  21.      2.5  Problems with and possible future directions for C++ templates
  22.  
  23.  
  24. 1. Pointer-to-member comparison
  25. ===============================
  26.  
  27. When the pointed-to member function is a virtual function, a comparison
  28. between two pointer-to-member-functions may not yield the results you expect.
  29. If one source file sets the value and a different source file does the
  30. comparison, the comparison fails because different function "thunks" are
  31. used to implement the call to the virtual function.  For example:
  32.  
  33.    hdr.h:  struct s { virtual foo(); };
  34.  
  35.    1.cpp:  #include "hdr.h"
  36.            extern void (s::*p)();  extern sub();
  37.            main () {
  38.               sub();   // Set the pointer.
  39.               if (p == s::foo) printf("OK\n");   // Will not print OK.
  40.               }
  41.  
  42.    2.cpp:  #include "hdr.h"
  43.            void (s::*p)();
  44.            sub() { p = s::foo; }
  45.  
  46. To get this to work requires either modifying linkers to support FORTRAN
  47. common-block style of code segments, or increasing the size of the
  48. representation of pointer-to-member-functions, neither of which seems
  49. especially desirable.
  50.  
  51.  
  52. 2.  Using templates
  53. ===================
  54.  
  55. Templates are a powerful extension to C++.  Templates allow you to define
  56. generic functions or classes.  Unlike macros, which are sometimes used to do
  57. the same thing (for example, generic.h), instantiations of templates are
  58. accompanied by full type checking.
  59.  
  60. However, there is a problem with using templates: you must ensure that for
  61. each distinct set of parameters to a template, there is only a single copy
  62. of an instantiated function or static class data member.
  63.  
  64. We have some reservations about methods we have seen for handling the single-
  65. copy problem automically.  One way, used by cfront 3.0, is to maintain a
  66. database of template instantiations and corresponding object code; we are
  67. concerned about the complexity and overhead of this approach.  Another
  68. approach, used by Borland C++, is to make proprietary extensions to the
  69. object-module format to support so-called "virtual" code and data segments,
  70. and to use a special linker.  We are concerned about the usability of High C++
  71. in multiple environments with an extension such as this.
  72.  
  73. So, for now, manual control over the single-copy problem is required.  The
  74. default operational mode of the compiler is to always generate instances of
  75. function templates and classes when they are used in a source module -- one
  76. instance in the source module is generated per set of parameters to the
  77. template.
  78.  
  79. The long and short of it is that High C++ currently requires the programmer to
  80. exercise manual control over this problem.  We show recommended ways of doing
  81. it here.
  82.  
  83.  
  84. 2.1  Ways to control the single-copy problem
  85. --------------------------------------------
  86.  
  87. If you are using templates defined locally within a single source module,
  88. there is no single-copy problem and no special care is needed.  Each source
  89. module has its own templates and instances:
  90.  
  91.    1.cpp:  template <class T> T min(T x, T y) {...}
  92.            . . .
  93.            int i = min(1,2) + min(3,4);
  94.  
  95.    2.cpp:  template <class T> T max(T x, T y) {...}
  96.            . . .
  97.            int j = max(1,2) + max(3,4);
  98.  
  99. Here each module contains an instance of a template function: min for 1.c and
  100. max for 2.c.  The problem arises only when you are using the same template in
  101. separate source modules:
  102.  
  103.    hdr.h:  template < class T > T min(T x, T y) {...}
  104.            template < class T > T max(T x, T y) {...}
  105.  
  106.    1.cpp:  #include "hdr.h"
  107.            int i = min(1,2) + max(3,4);
  108.  
  109.    2.cpp:  #include "hdr.h"
  110.            int j = min(1,2) + max(3,4);
  111.  
  112. Here the object modules for 1.cpp and 2.cpp both contain definitions of
  113. min(int,int) and max(int,int), and the linker will complain about a duplicate
  114. definition.
  115.  
  116. The way to prevent duplicate definitions is to turn off automatic template
  117. instantiations when compiling.  You turn them off for template functions by
  118. turning off the toggle Auto_func_instantiation:
  119.  
  120.    1.cpp:  pragma off(Auto_func_instantiation);
  121.            #include "hdr.h"
  122.            int i = min(1,2) + max(3,4);
  123.  
  124.    2.cpp:  pragma off(Auto_func_instantiation);
  125.            #include "hdr.h"
  126.            int j = min(1,2) + max(3,4);
  127.  
  128. The toggle must be turned off in the presence of the function template
  129. definition -- not the calls to the function template.  Essentially, the
  130. compiler records the setting of the toggle when it encounters the function
  131. template.  For a non-inline function template encountered with the toggle off,
  132. there are no instantiations of the function template bodies in the source
  133. code.
  134.  
  135. But now you have two modules, both of which make external references to
  136. min(int,int) and max(int,int), and the linker will complain of missing
  137. functions.
  138.  
  139. You can provide the necessary functions as follows: in a single new source
  140. module, include calls to the function templates with the appropriate
  141. arguments, and keep the Auto_func_instantiations toggle on.  The object code
  142. for this module contains the required instantiated functions.
  143.  
  144. We recommend you place these calls in the module in such a way that the
  145. functions are never actually called at run time, and the code for calling them
  146. is never actually generated by the compiler.  Here is a convenient way to do
  147. this with macros:
  148.  
  149.    fti.cpp:  #include "hdr.h"
  150.              #define DONTCALL(f) (0 && f)
  151.              static void dummy() {
  152.                 DONTCALL(min(1,1));
  153.                 DONTCALL(max(1,1));
  154.                 };
  155.  
  156. Because of the conditional in the macro, the body for dummy() is empty.  Yet
  157. the object module for this source module contains the definitions of
  158. min(int,int) and max(int,int).
  159.  
  160.  
  161. 2.2  Class templates
  162. --------------------
  163.  
  164. The examples above centered on function templates, but similar considerations
  165. apply to class templates.  A class template must always be instantiated when
  166. it is used -- since the resultant type is required for further processing --
  167. but the single-copy problem applies to the non-inline class member functions
  168. and static data members.  Again, if you use a class template only locally to a
  169. source module there is no problem; sharing an instantiation of a member
  170. function or data member is the problem.
  171.  
  172. As with function templates, the default mode of the compiler is to always
  173. generate instances of class members when the class is used in a source module,
  174. and when the definitions of those members is likewise presented to the
  175. compiler (you could omit the definitions if you wanted).  You can turn off
  176. this automatic instantiation by turning off toggle
  177. Auto_class_member_instantiation.  Then you must provide another source module
  178. with the toggle on, in which you define the class members.  For example:
  179.  
  180.    stack.h:  template < class T > class stack {
  181.                 T *v, *p; int sz;
  182.              public:
  183.                 stack(int);
  184.                 ~stack() { delete[] v; }
  185.                 void push(T);
  186.                 T pop() { return *--p; }
  187.                 };
  188.              template<class T> void stack<T>::push(T a) { *p++ = a; }
  189.              template<class T>      stack<T>::stack(int s) {
  190.                 v = p = new T[sz=s];
  191.                 }
  192.  
  193.    3.cpp:    pragma Off(Auto_class_member_instantiation);
  194.              #include "stack.h"
  195.              f() {
  196.                 stack<int> I(10); stack<float> F(20);
  197.                 I.push(1);    F.push(1.0);
  198.                 I.pop();      F.pop();
  199.                 }
  200.  
  201.    4.cpp:   pragma Off(Auto_class_member_instantiation);
  202.             #include "stack.h"
  203.             f() {
  204.                stack<int> I(10); stack<float> F(20);
  205.                I.push(2);    F.push(2.0);
  206.                I.pop();      F.pop();
  207.                }
  208.  
  209. Here, both modules contain external references to stack<int>::push(int),
  210. stack<int>::stack(int), stack<float>::push(float), and
  211. stack<float>::stack(float).  Note that there are no references to the inline
  212. members (such as pop) of stack<int> and stack<float>; these inline members are
  213. in fact generated by the compiler and inlined.  The external references are
  214. made only to the non-inline functions and static data members.
  215.  
  216. You can provide the push and constructor functions by compiling the following
  217. module that simply refers to the two stack types:
  218.  
  219.    cti.cpp:  #include "stack.h"
  220.              typedef stack<int>   dummy1;
  221.              typedef stack<float> dummy2;
  222.  
  223.  
  224. 2.3  Checking template usage
  225. ----------------------------
  226.  
  227. You can get an idea of which templates were used in a compilation by turning
  228. on toggle Print_template_usage.  Both function templates and class templates
  229. are printed and, for a class template, its members are printed indented below
  230. the class template.  There is a single character in the leftmost column:
  231.  
  232.    I   -- means the compiler instantiated this.
  233.    e   -- means undefined (it's external) and you must supply it.
  234.    U   -- means the user defined a special version of a function, class
  235.           member, or class template.
  236.  
  237. For example, the result from compiling 3.cpp above is:
  238.  
  239. Template usage:
  240. I   stack<int>     (at "3.cpp",L5/C7)
  241. e      stack(int)  (at "stack.h",L4/C11)
  242. e      void push(int)    (at "stack.h",L6/C16)
  243. I   stack<float>   (at "3.cpp",L5/C25)
  244. e      stack(int)  (at "stack.h",L4/C11)
  245. e      void push(float)  (at "stack.h",L6/C16)
  246.  
  247. Here we see that the two stack classes are instantiated (I) but the two member
  248. functions are external (e).  Compiling cti.cpp you see them instantiated:
  249.  
  250. Template usage:
  251. I   stack<int>     (at "cti.cpp",L2/C11)
  252. I      stack(int s)   (at "stack.h",L10/C26)
  253. I      void push(int a)  (at "stack.h",L9/C26)
  254. I   stack<float>   (at "cti.cpp",L3/C11)
  255. I      stack(int s)   (at "stack.h",L10/C26)
  256. I      void push(float a)   (at "stack.h",L9/C26)
  257.  
  258.  
  259. 2.4  A note on terminology
  260. --------------------------
  261.  
  262. The ARM talks about "function templates" and "template functions".  A template
  263. function is an instantiation of a function template.  Be aware of this
  264. distinction when reading the ARM.  We think this terminology is unfortunate;
  265. the two phrases are too close and are easily confused.  We've seen it happen
  266. repeatedly at ANSI C++ standards meetings.  So we use "instantiation" or
  267. "instance" rather than "template function", and will move to make a similar
  268. change in the C++ draft standard.
  269.  
  270. "class templates" and "template classes" are similarly related, and we vote
  271. for a similar change in terminology.
  272.  
  273. 2.5  Problems with and possible future directions for C++ templates
  274. -------------------------------------------------------------------
  275.  
  276. Instantiating a function template requires an exact match of the function
  277. formal-parameter types and the actual-parameter types.  This can be somewhat
  278. of a nuisance.  For example, suppose you generalize the ANSI C bsearch()
  279. routine with a template:
  280.  
  281.    template <class T> T *bsearch(const T key, const T *base, int nmemb);
  282.  
  283. Because you've used const, your generic search routine "promises" never to
  284. clobber the elements being searched, nor the key.  This is a valuable promise.
  285. But when you try to call bsearch():
  286.  
  287.    extern int a[10];
  288.    int *solution = bsearch(123, a, 10);        // (A)
  289.  
  290. the call fails, because 123 is not a const, and a is not of type pointer-to-
  291. const.  In fact, you have to write:
  292.  
  293.    extern int a[10];
  294.    int *solution = bsearch((const int)123, (const int *)a, 10);
  295.  
  296. One way to alleviate this problem is to define an additional inline template
  297. that allows non-const parameters, but which calls the "real" one:
  298.  
  299.    template <class T> inline T *bsearch(T key, T *base, int nmemb) {
  300.       bsearch((const T)key, (const T*)base, nmemb);
  301.       }
  302.  
  303. This would allow the call (A) to work; the second template is called, which
  304. turns around and calls the first.  Since the second is inline, there is no
  305. performance penalty.
  306.  
  307. There have been requests to loosen up the exact-match rule to permit a non-
  308. const parameter to "matched" with a const parameter in a function template.
  309. Turning on the High C++ toggle Template_trivial_conversions permits so-called
  310. trivial conversions (in the parlance of the ARM) to be allowed when matching
  311. arguments to function templates.  This allows call (A) to work without
  312. introducing the intermediate inline template.
  313.