[ROOT] Problem compiling template classes with multiple arguments.

From: Gora Mohanty (gora@coyote.ucr.edu)
Date: Tue Feb 20 2001 - 05:10:35 MET


Hello,
  I am stumped while trying to compile a class with more than one template
argument. I have made up ClassDefTT, ClassDefTT2, ClassImpTT2 macros in
analogy to the corresponding ones for the single-argument template classes.
Everything almost works, except that the declaration of a friend operator
function seems to exercise a bug in CINT. A trivial example that reproduces
the problem is attached in several files: test.h, test.cxx, ClassDefTT.h, and
LinkDef.h. These compile and work under g++. I am using ROOT v3.00.02 (also
tried 3.00.05) on a Linux SUSE 6.1 box, upgraded to the 2.4.1 kernel.

  The reason that I am fairly sure that this is a CINT bug is that if I give
a default argument to the class U, e.g., replace the third line in the test.h
file with
  template<class T, class U=T> class A;
and replace all A<T, U> with A<T> (so that U now having the default value
above), rootcint correctly generates the CINTDict file. The rootcint command
line is 
  rootcint -f CINTDict.cxx -c -p -I. -I${ROOTSYS}/include test.h LinkDef.h
The messages I get from rootcint are,
class A<int,int> in test.h line 9 original base of virtual func
Note: Link requested for undefined class const  FILE: LINE:0
Note: Link requested for undefined class int>operator+<>(constA<int,int>&,int&)  FILE: LINE:0
Class const: Streamer() not declared
Class const: ShowMembers() not declared
Class int>operator+<>(constA<int,int>&,int&): Streamer() not declared
Class int>operator+<>(constA<int,int>&,int&): ShowMembers() not declared
Class int>operator+<>(constA<int,int>&,int&): Class_Name() and initialization object not declared

Thanks for any help.

Regards,
Gora



#include <Rtypes.h>
#include <ClassDefTT.h>

template<class T, class U> class A;

template<class T, class U> const A<T, U> operator+(const A<T, U>&, U&);

template<class T, class U>
class A {
private:
  T i;
public:
  A(T ii = 0) : i(ii) {}
  friend const A<T, U> operator+ <>(const A<T, U>&, U&);
  ClassDefTT(A, 1)
};
ClassDefTT2(A, T, U)


// #include <iostream>
#include "test.h"
ClassImpTT(A, T, U)

template<class T, class U>
const A<T, U> operator+(const A<T, U>& a, U& b) { return A<T, U>( a.i + b ); }


// Include file for template classes with two parameters. Adapted from
// Rtypes.h.
#ifndef ClassDefTT_INC
#define ClassDefTT_INC
//---- ClassDefTT macros for templates with two parameters ----------------
// ClassDefTT  corresponds to ClassDef
// ClassDefTT2 goes in the same header as ClassDefT but must be
//             outside the class scope
// ClassImpTT  corresponds to ClassImp
extern void AddClass(const char *, Version_t, VoidFuncPtr_t, Int_t);
extern void RemoveClass(const char *);
#define ClassDefTT(name,id) \
private: \
   static TClass *fgIsA; \
public: \
   static TClass *Class(); \
   static const char *Class_Name(); \
   static Version_t Class_Version() { return id; } \
   static void Dictionary(); \
   virtual TClass *IsA() const { return name::Class(); } \
   virtual void ShowMembers(TMemberInspector &, char *); \
   virtual void Streamer(TBuffer &); \
   void StreamerNVirtual(TBuffer &b) { name::Streamer(b);} \
   static const char *DeclFileName() { return __FILE__; } \
   static int DeclFileLine() { return __LINE__; } \
   static const char *ImplFileName(); \
   static int ImplFileLine();

#define _ClassInitTT_(name,Tmpl_A,Tmpl_B) \
   template <class Tmpl_A, class Tmpl_B> class _NAME2_(R__Init,name) { \
      public: \
         _NAME2_(R__Init,name) (Int_t pragmabits) { \
            AddClass(name<Tmpl_A, Tmpl_B>::Class_Name(), \
                     name<Tmpl_A, Tmpl_B>::Class_Version(), \
                     &name<Tmpl_A, Tmpl_B>::Dictionary, pragmabits); \
         } \
         _NAME3_(~,R__Init,name) () { \
            RemoveClass(name<Tmpl_A, Tmpl_B>::Class_Name()); \
         } \
   };

#define ClassDefTT2(name,Tmpl_A,Tmpl_B) \
   template <class Tmpl_A, class Tmpl_B> \
     TBuffer &operator>>(TBuffer &, name<Tmpl_A, Tmpl_B> *&); \
   _ClassInitTT_(name,Tmpl_A,Tmpl_B)

#define _ClassImpTT_(name,Tmpl_A, Tmpl_B) \
   template <class Tmpl_A, class Tmpl_B> \
     TClass *name<Tmpl_A, Tmpl_B>::Class() \
     { if (!fgIsA) name<Tmpl_A, Tmpl_B>::Dictionary(); return fgIsA; } \
   template <class Tmpl_A, class Tmpl_B> \
     const char *name<Tmpl_A, Tmpl_B>::ImplFileName() { return __FILE__; } \
   template <class Tmpl_A, class Tmpl_B> \
     int name<Tmpl_A, Tmpl_B>::ImplFileLine() { return __LINE__; } \
   template <class Tmpl_A, class Tmpl_B> \
     TClass *name<Tmpl_A, Tmpl_B>::fgIsA = 0;

#define ClassImpTT(name,Tmpl_A, Tmpl_B) \
   template <class Tmpl_A, class Tmpl_B> \
     void name<Tmpl_A, Tmpl_B>::Dictionary() { \
     TClass *c = CreateClass(Class_Name(),   Class_Version(), \
                             DeclFileName(), ImplFileName(),  \
                             DeclFileLine(), ImplFileLine()); \
      fgIsA = c; \
   } \
   _ClassImpTT_(name,Tmpl_A, Tmpl_B)
#endif  // #ifndef ClassDefTT_INC
//@@@@@@@@@@@@@@@@@@@@@@@@@ END OF FILE @@@@@@@@@@@@@@@@@@@@@@@@@


#ifdef __CINT__
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;

#pragma link C++ class A<Int_t, Int_t>;
#endif



This archive was generated by hypermail 2b29 : Tue Jan 01 2002 - 17:50:37 MET