Templates, ACLiC and LinkDef.h

Dear ROOTers,

I’m a bit confused in the use of “LinkDef.h” files when I try to compile with ACLiC some source code with templated classes. In particular, I would like to compile within a ROOT interactive session the libraries with “.L blabla.cpp+” in such a way that they are available in the interactive session as well as in other unnamed or named macros.

In the following code I have two templated classes: the second one, “testmap”, is just to test the methods of the first one.


/////////////////////////////////////////
// File AnalysisClasses.hpp
/////////////////////////////////////////

namespace RD51TB
{
  template<typename chtype, typename maptype> 
  class MappedChannel
  {
  public:
    chtype ich;
  public:
    double X()     { return maptype::GetCoord(ich,1); };
    double Y()     { return maptype::GetCoord(ich,2); };
    double Z()     { return maptype::GetCoord(ich,3); };
    double r()     { return maptype::GetCoord(ich,4); };
    double phi()   { return maptype::GetCoord(ich,5); };
    double theta() { return maptype::GetCoord(ich,6); };

    //ROOT macro for persistence support (no vtable)
    ClassDefNV(MappedChannel, 1);    //MappedChannel
  };
  
  template<typename chtype> 
  class testmap
  {
  public:
    static double GetCoord(chtype ch, int coord);
    
    ClassDefNV(testmap, 0);    //testmap    
  };   
}
//---------------------------------------------------------------------------------------------------------

////////////////////////////////////////////
// File AnalysisClasses.cpp
////////////////////////////////////////////

#include "AnalysisClasses.hpp"

namespace RD51TB
{
  template<typename chtype> 
  double testmap<chtype>::GetCoord(chtype ch, int coord)
  {
    return ch+coord; //just for testing..
  }
}

templateClassImp(RD51TB::MappedChannel);
templateClassImp(RD51TB::testmap);

//-----------------------------------------------------------------------------------------------

After “.L AnalysisClasses.cpp+” the two classes are not available in the interpret environment, because, as I read in the manual, I have to specify:
#pragma link C++ class testmap;
#pragma link C++ class MappedChannel<int,testmap>+;

Now it is unclear the role of the “LinkDef.h” file (or the “AnalysisClassesLinkDef.h” file). From the manual it seems that I can specify the previous two “pragmas” in such files, but whatever combination I try, my feeling is that such files are just ignored by the ACLiC compilation.
Maybe they are used only when you manually create the dictionary with the “rootcint” command… is this correct?

In order to have the above mentioned classes available in the ROOT prompt I have to insert the two pragmas at the end of the .cpp file. Not too bad, for now.

Assume that I want to split the code in two translation units: the class “MappedChannel” will go to “GenericClasses.{hpp,cpp}” files and in “SpecificClasses.{hpp,cpp}” I’ll put for example the testmap class, or any other specific class that I could need for a specific situation.

Now I’m in trouble… where should I put the pragma statements? I would like to put them in the second translation unit, because the required template specialization are specific of the situation.
The compilation seems ok, but the classes are not available in the command lines…
Where am I wrong?

You can find the {Generic,Specific}Classes.{hpp,cpp} in the atteched .tgz file.

Finally, I have also two somehow related questions:

  1. what is the role of the ClassImp macros? Are they just used for the HTML documentation production?
  2. I tried to link “testmap” with the “-” option:
    pragma link C++ class testmap-;
    since in the .hpp I have not asked for input/output facilities (“ClassDefNV(…,0)”, but the compiler complains about the missing “Streamer” method…

EDIT: ops… I forgot the attachment… now it is there
testtemplate.tgz (716 Bytes)

Hi,

At this moment, ClassImp is used only to register the file name where the class implementation is ; the main consumer of this information in indeed THtml.

[quote] From the manual it seems that I can specify the previous two “pragmas” in such files, but whatever combination I try, my feeling is that such files are just ignored by the ACLiC compilation.[/quote]ACLiC’s convention to find the linkdef file associate with a script it compiles is declared/customized by the rootrc key ‘ACLiC.Linkdef’ and (see $ROOTSYS/etc/system.rootrc) it defaults to _linkdef.
Thus for “.L AnalysisClasses.cpp+” you need to name your linkdef file “AnalysisClasses_linkdef.h”

Note that IF you script/header is not included in any other scripts that will be compiled by ACLiC you can simply put the #pragma link statement inside the file. So for example in your case you could add to AnalysisClasses.cpp the lines:#ifdef __MAKECINT__ #pragma link C++ class testmap<int>; #pragma link C++ class MappedChannel<int,testmap<int>>+; #endifthe #ifdef is necessary to hide the pragma from the compiler.

[quote]2) I tried to link “testmap” with the “-” option:[/quote]The - options does not mean disable I/O. When you have a ClassDef, it means explicitly that you want to be implementing the Streamer function yourself.

Cheers,
Philippe.

[quote]I would like to put them in the second translation unit, because the required template specialization are specific of the situation.
The compilation seems ok, but the classes are not available in the command lines…[/quote]You example worked as is for me:[code]root [0] .L SpecificClasses.cpp+
Info in TUnixSystem::ACLiC: creating shared library /Users/pcanal/Downloads/./SpecificClasses_cpp.so
root [2] RD51TB::testmap a
root [3] RD51TB::MappedChannel<int,RD51TB::testmap> b
root [4] .class RD51TB::MappedChannel<int,RD51TB::testmap>

class RD51TB::MappedChannel<int,RD51TB::testmap > //MappedChannel
size=0x4 FILE:SpecificClasses_cpp.so LINE:-1
(tagnum=2885,voffset=-1,isabstract=0,parent=2883,gcomp=0:-1,funcs(dn21=~xcpd)=0)
List of base class--------------------------------------------------------
List of member variable---------------------------------------------------
Defined in MappedChannel<int,RD51TB::testmap >
SpecificClasses_cpp.so -1 0xffffffffffffffff int ich
SpecificClasses_cpp.so -1 0x0 private: static TClass* fgIsA
List of member function---------------------------------------------------
filename line:size busy function type and name (in MappedChannel<int,RD51TB::testmap >)
SpecificClasses_cpp.so -1:-1 0 public: void ~MappedChannel<int,RD51TB::testmap >(void);
SpecificClasses_cpp.so -1:-1 0 public: double X(void);
SpecificClasses_cpp.so -1:-1 0 public: double Y(void);
SpecificClasses_cpp.so -1:-1 0 public: double Z(void);
SpecificClasses_cpp.so -1:-1 0 public: double r(void);
SpecificClasses_cpp.so -1:-1 0 public: double phi(void);
SpecificClasses_cpp.so -1:-1 0 public: double theta(void);
SpecificClasses_cpp.so -1:-1 0 public: static TClass* Class(void);
– Press return for more – (input [number] of lines, Cont,Step,More) [/code]

Cheers,
Philippe.