Topic: A template question


Author: b91926@fsgi01.fnal.gov (David Sachs)
Date: 21 Apr 1994 10:34:54 -0500
Raw View
gary@cuok.cameron.edu (gary huckabay) writes:

>Consider the following program.

...

>When I compile this on an HP minicomputer (unix, hp compiler), it compiles,
>links and executes fine.  When I attempt to build it on a DOS machine
>using turbo C++ 3.0, I get the following errors(2) messages.  Can anyone
>tell me what the problem is?

>linker error: undefined symbol Array<string>::operator =
> (Array<string>near&)
>linker error: undefined symbol Array<complex>::operator =
> (Array<complex>near&)

Borland C++ compilers have compile time options that control
the instantiation of template functions. You may have these
options set wrong.

If necessary specify the proper compiler option, on the command
line, in your project, or as a #pragma within your source code.




Author: jamshid@ses.com (Jamshid Afshar)
Date: Tue, 26 Apr 1994 03:09:35 GMT
Raw View
Redirected to comp.lang.c++.

In article <2p66eu$lv4@fsgi01.fnal.gov>,
David Sachs <b91926@fsgi01.fnal.gov> wrote:
>gary@cuok.cameron.edu (gary huckabay) writes:
>>Consider the following program.
>>[it builds on HP, gives errors on Borland Turbo C++ 3.0 compiler]

Btw, I would highly recommend using BC++ 4.0 or at least BC++ 3.1
since Borland improved templates quite a bit.  Then agin, if you're
used to a Cfront-based implementation, TC++ 3.0 shouldn't frustrate
you much.

>>linker error: undefined symbol Array<string>::operator =
>> (Array<string>near&)
>>linker error: undefined symbol Array<complex>::operator =
>> (Array<complex>near&)
>
>Borland C++ compilers have compile time options that control
>the instantiation of template functions. You may have these
>options set wrong.

You don't have to mess with these options if you just #include the
array.cc in array.h.  Current compilers implementing templates seem to
fall into two categories: those that require you to include all the
non-inline template functions and those that don't.  I have something
like the following in all my class template headers:

 // list.h
 #ifndef LIST_H
 #define LIST_H

 template<class T> class List {/*...*/};
 /* inline List<T> functions */

 #ifdef NEED_CC      /* include non-inline template function defs? */
 #include "list.cc"  /* probably needs its own #ifndef wrapper */
 #endif

 #endif // LIST_H

Just define NEED_CC on the command-line for most (all?) PC compilers
and g++, but not Cfront-based implementations.  I prefer my method to
#include'ing the .cc in user modules or messing with explicit
instantiation using #pragmas.  I don't think putting all your
non-inline template function definitions in the header is a good idea
even if current compilers seem to allow it.  Only look into explicit
instantiation if you start hitting compiler/linker limits or compile
times get unacceptably high.

Btw, Stroustrup writes in _The Design and Evolution of C++_ (an
excellent book for catching up on new ANSI/ISO features) that a method
for explicit (*OPTIONAL*, thank god) instantiation of templates was
accepted.  This was done so that users or library writers have the
option of (possibly) speeding up their compiles and links.  It also
allows library writers to catch errors in template functions when
building a library instead of waiting until link time.  The syntax is
something like (sorry, don't have the book here):

 template class List<String>;
 template void sort(List<String>);

Jamshid Afshar
jamshid@ses.com




Author: gary@cuok.cameron.edu (gary huckabay)
Date: Tue, 19 Apr 1994 06:56:10 GMT
Raw View
Consider the following program.

// file array.h
#ifndef ARRAY_H
#define ARRAY_H
template <class T> class Array {
     T* p;
     int count;
public:
     Array(int n=0) : p(new T[n]), count(n) {}
     ~Array() {delete [] p;}
     T& operator[] (int ix) {return p[ix];}
     Array<T>& operator= (Array<T>&);
};
#endif

// file array.C
#include "array.h"

template <class T>
Array<T>& Array<T>::operator= (Array<T>&a) {
     if (p) delete [] p;
     p = new T[count = a.count];
     for (int i=0; i<a.count; i++)
          p[i] = a.p[i];
     return *this;
}

// file main.C
#include <iostream.h>
#include "array.h"
#include "complex.h"  // defined in the normal way
#include "stringc.h"  // defined in the way that 63,000
    // textbook writers have defined it.

void main() {

     Array<complex> z(10), w(10);
     z[0] = complex(1.0, 2.0);
     z[1] = complex(-2.0, 1.0);
     z[2] = complex(3.0, 2.0);
     for (int i=3; i<10; i++)
         z[i] = z[i-3]*z[i-1] + z[i-2];
     w = z;
     for (i=0; i<10; i++)
         cout << w[i] << endl;  //Note w, not z!
     cout << endl;

     Array<string> s(7), t(7);
     s[0] = string("AAA");
     s[1] = "BB" + s[0];
     s[2] = s[1] + "CC";
     for (i=3; i<7; i++)
          s[i] = s[i-3] + s[i-1];
     t = s;
     for (i=0; i<7; i++)
          cout << t[i] << endl;    //Note t, not s!
     cout << endl;
}

When I compile this on an HP minicomputer (unix, hp compiler), it compiles,
links and executes fine.  When I attempt to build it on a DOS machine
using turbo C++ 3.0, I get the following errors(2) messages.  Can anyone
tell me what the problem is?

linker error: undefined symbol Array<string>::operator =
 (Array<string>near&)
linker error: undefined symbol Array<complex>::operator =
 (Array<complex>near&)





Author: rfg@netcom.com (Ronald F. Guilmette)
Date: Mon, 1 Nov 1993 05:47:17 GMT
Raw View
In article <2a0tif$6p8@wsinpi02.win.tue.nl> watson@wsinpi02.win.tue.nl (Bruce W. Watson) writes:
>I have a question that relates to the standard. I have a class template
>definition as follows:
>
>template <class T> class A : public T {
>public:
> A<T>& a( A<T>& r );
>};
>
>For each instantiation of the template, for example:
>class B {
>// some stuff
>};
>
>(and then sometime later, a use of A<B>). I would like to write instantiation
>specific versions of the function A<B>::a()  (In fact, I don't mind ALWAYS
>having to do that, for all instantiations --- see the reason below.)
>I realize that writing instantiation specific versions is commonly done, but
>is it perfectly legal to not even provide a generic version of the function
>a() ?

In general, you need not do things which the standard (or the defacto
standard) doesn't say you have to do.

I don't know of anyplace where it says that you have to provide definitions
of things that you do not even reference.

What worries me is just the opposite... I also don't know where either the
ARM or the current X3J16 working paper say that you *must* provide definitions
for things (e.g. function, object, templates, etc.) which you *do* reference.

--

-- Ronald F. Guilmette, Sunnyvale, California -------------------------------
------ domain address: rfg@netcom.com ---------------------------------------
------ uucp address: ...!uunet!netcom.com!rfg -------------------------------