Topic: C++ template problems


Author: cox@cbnewsm.cb.att.com (michael.cox)
Date: Fri, 26 Mar 1993 03:22:04 GMT
Raw View
/*
The following code demonstrates a bug(?) in cfront 3.0.2.  If it isn't a bug
could somebody explain to me why it shouldn't work.  The ARM says that

 template-argument:
  type-argument
  argument-declaration <<<

I think a "Field::Type type" is an argument declaration, and therefore should
compile.

What I REALLY would like to do is:

class Field // Abstract class defining interface
{
public:
 virtual int maxSize() const = 0;
 virtual const char *name() const = 0;
};

template<const char *name, int size>
class Field: public Field
{
public:
 virtual int maxSize() const { return size; }
 virtual const char *name() const { return name; }
};

typedef Field<"RACCT", 14> RACCT;

Note that the template class and the abstract class have the same name.

When I compile the above with cfront 3.0.2, it says that the "const char *"
template argument is not implemented.  That sounds like what I want to do
will eventually be legal in C++.

What isn't clear is why the template class name has to be unique.  Since
the template arguments can be encoded into the "class signature" much like
function arguments are encoded into the function signature, I should be
able to define "class Field {}" and "template<class T> class Field {}" in
the same scope.

I don't know much about how C++ compilers are implemented, so I don't know
if what I'm asking for is hopelessly ambiguous and therefore impossible to
implement.  It sure would be a nice feature...

Another "feature" of templates that bothers me is that they can only be
defined globally.  If I'm using a GUI application framework from one
vendor and a database application framework from another vendor, the
following scenario is possible:

 // defines template<T> class LinkedList
 #include "GUIAppFramework.h"

 // defines template<T> class LinkedList also
 #include "DBAppFramework.h" // syntax error


The application vendors could try to nest the template classes, i.e.

class GUIAppFramework
{
 template<class T>
 class LinkedList {};
};

class DBAppFramework
{
 template<class T>
 class LinkedList {};
};

but this generates the syntax errors:

 CC bug4.c
 "bug4.c", line 5: error: nested template class LinkedList
 "bug4.c", line 5: error:  template class ? -- ? already declared as typedef ()
 sorry, cannot recover from previous error
 2 errors

In the ARM, Stroustrup gives the following justification for globally scoped
template classes:

 The restriction to global templates is stronger than necessary;
 some templates could be handled in some local and nested contexts.
 Some, however -- such as a template for a function definition defined
 within a function -- cannot, and a general and simple restriction
 seems more sensible than a detailed and possibly subtle list.

As C++ application frameworks using templates become more common,
my example problem is going to become more common and we'll need template
classes that obey scope rules.  Are there any other reasons why template
classes are globally scoped?

*/
#include <iostream.h>
#include <iomanip.h>
#include <memory.h>


class Field
{
public:
 enum Type
 {
  BAD_TYPE,
  RECORD_TYP,
  RACCT,
  BSA,
  //...
 };


 virtual Type type() const = 0;
 virtual int maxSize() const = 0;
 virtual const char *name() const = 0;

protected:
 Field(): data(NULL) {}

  Field(const Field &f)
  {
   data = new char[f.maxSize()];
  memcpy(data,f.data, f.maxSize());
  }

 Field(int size)
 {
  data = new char[size];
  memset(data, ' ', size);
 }

 Field(const char *raw_data, int size)
 {
   data = new char[size];
  memcpy(data, raw_data, size);
 }

 virtual ~Field() { delete data; }

 int isEqual(const Field &f) const
 {
  return(memcmp(data, f.data, maxSize())==0);
 }

 void assign(const Field &f)
 {
  if (f.maxSize()<maxSize())
  {
   // Copy the data into the new data buffer
   memcpy(data, f.data, f.maxSize());

   // Blank out the rest of the field.
   memset(&data[f.maxSize()], ' ', maxSize()-f.maxSize());
  }
  else
   memcpy(data,f.data, maxSize());
 }

public:
 int operator==(const Field &f)
 {
  return(type()==f.type() && isEqual(f));
 }

 Field &operator=(const Field &f)
 {
  assign(f);
  return(*this);
 }

private:
 char *data;
};


template<Field::Type type, int size>
class FieldClass /* wish I could just say Field... */: public Field
{
 static const char *Name;

public:
 static FieldClass<type, size> BLANK;

 FieldClass(): Field(size) {}
 FieldClass(const FieldClass<type, size> &f): Field(f) {}
 FieldClass(const char *raw_data): Field(raw_data, size) {}

 virtual int maxSize() const { return(size); }
 virtual Type type() const { return(type); }
 virtual const char *name() const { return(Name); }
};

// Would prefer to just say "typedef Field<Field::Type::RACCT, 14> RACCT".
typedef FieldClass<Field::Type::RACCT, 14> RACCT;

const char *RACCT::Name = "RACCT";
const RACCT RACCT::BLANK;

RACCT racct;

Field *p = &racct;

/*
CC  bug3.c:
"bug3.c", line 195: error:  Field::Type:: RACCT  -- Field::Type not a class name
"bug3.c", line 195: error:  RACCT undefined
"bug3.c", line 195: error:  template argument for formal: type is not a suitable
 constant.
"bug3.c", line 190: error: bad return value type for  FieldClass <"bug3.c", line
 190: sorry, cannot recover from earlier errors
4 errors
*/
--

==========================================================================
Michael H. Cox   ARPA:  ?
AT&T CFO   UUCP:  attmail!cbs1!cox