Skip to content

Commit

Permalink
Workaround a fundamental ROOT issue with ClassDef and dictionaries.
Browse files Browse the repository at this point in the history
ROOT needs reflection information about classes. One way to incorporate this
information is to use a ClassDef macro, which adds a few members to the
classes. For example, how to read/write the class on disk (aka streamer).
The ClassDef adds forward declaration of a streamer function (and a few others)
in the body of the class. Later on a special tool (aka rootcling) defines the
forward declarations unless told otherwise by the dictionary generation driver
(aka Linkdef file). Simply explained, the ROOT IO-aware class *declare* a few
functions, whoose definitions will come from a dictionary.

As always the interesting part comes when C++ templates come around. Depending
on the order of the header files, which appear in the dictionaries the template
class can be instantiated. For example:
A.h: template<class T> struct TMyClassT { ...; ClassDef(MyClassT, 1); };
B.h: struct S { TMyClassT<int> var; };
G__: #include "A.h" // #1
     #include "B.h" // #2
    // Definitions of the contents of the ClassDef.
B.h forces an implicit instantiation of TMyClassT *before* the compiler can see
the definitions of the ClassDef. Namely,
template <> TClass *TMyClassT<int>::Class(){} is seen after #2 when the compiler
has instantiated it. C++ 14.7.3/6 explains it as:
"If a template, a member template or a member of a class template is explicitly
specialized then that specialization shall be declared before the first use of
that specialization that would cause an implicit instantiation to take place, in
every translation unit in which such a use occurs; no diagnostic is required."
Saying that what we do makes the TU ill-formed but no diagnostic is required.

Modules are more strict in that respect and issue diagnostics. This commit
introduces a workaround while the actual solution to the problem is being
developed. As Axel and I discussed a real solution would be to implement a
ClassDef macro which inlines the contents, disallowing custom streamers
covering 99.9% of the cases.
  • Loading branch information
vgvassilev committed Nov 13, 2015
1 parent e49515c commit 5197ed6
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 0 deletions.
12 changes: 12 additions & 0 deletions math/matrix/inc/TMatrixT.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,18 @@ template<class Element> class TMatrixT : public TMatrixTBase<Element> {
ClassDef(TMatrixT,4) // Template of General Matrix class
};

#ifndef __CINT__
// When building with -fmodules, it instantiates all pending instantiations,
// instead of delaying them until the end of the translation unit.
// We 'got away with' probably because the use and the definition of the
// explicit specialization do not occur in the same TU.
//
// In case we are building with -fmodules, we need to forward declare the
// specialization in order to compile the dictionary G__Matrix.cxx.
template <> TClass *TMatrixT<double>::Class();
#endif // __CINT__


template <class Element> inline const Element *TMatrixT<Element>::GetMatrixArray() const { return fElements; }
template <class Element> inline Element *TMatrixT<Element>::GetMatrixArray() { return fElements; }

Expand Down
12 changes: 12 additions & 0 deletions math/matrix/inc/TMatrixTBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,18 @@ template<class Element> class TMatrixTBase : public TObject {
ClassDef(TMatrixTBase,5) // Matrix base class (template)
};

#ifndef __CINT__
// When building with -fmodules, it instantiates all pending instantiations,
// instead of delaying them until the end of the translation unit.
// We 'got away with' probably because the use and the definition of the
// explicit specialization do not occur in the same TU.
//
// In case we are building with -fmodules, we need to forward declare the
// specialization in order to compile the dictionary G__Matrix.cxx.
template <> TClass *TMatrixTBase<double>::Class();
#endif // __CINT__


template<class Element> Element TMatrixTBase<Element>::SetTol(Element newTol)
{
const Element oldTol = fTol;
Expand Down
11 changes: 11 additions & 0 deletions math/matrix/inc/TMatrixTSparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,17 @@ template<class Element> class TMatrixTSparse : public TMatrixTBase<Element> {
ClassDef(TMatrixTSparse,3) // Template of Sparse Matrix class
};

#ifndef __CINT__
// When building with -fmodules, it instantiates all pending instantiations,
// instead of delaying them until the end of the translation unit.
// We 'got away with' probably because the use and the definition of the
// explicit specialization do not occur in the same TU.
//
// In case we are building with -fmodules, we need to forward declare the
// specialization in order to compile the dictionary G__Matrix.cxx.
template <> TClass *TMatrixTSparse<double>::Class();
#endif // __CINT__

template <class Element> inline const Element *TMatrixTSparse<Element>::GetMatrixArray () const { return fElements; }
template <class Element> inline Element *TMatrixTSparse<Element>::GetMatrixArray () { return fElements; }
template <class Element> inline const Int_t *TMatrixTSparse<Element>::GetRowIndexArray() const { return fRowIndex; }
Expand Down
10 changes: 10 additions & 0 deletions math/matrix/inc/TMatrixTSym.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,16 @@ template<class Element> class TMatrixTSym : public TMatrixTBase<Element> {

ClassDef(TMatrixTSym,2) // Template of Symmetric Matrix class
};
#ifndef __CINT__
// When building with -fmodules, it instantiates all pending instantiations,
// instead of delaying them until the end of the translation unit.
// We 'got away with' probably because the use and the definition of the
// explicit specialization do not occur in the same TU.
//
// In case we are building with -fmodules, we need to forward declare the
// specialization in order to compile the dictionary G__Matrix.cxx.
template <> TClass *TMatrixTSym<double>::Class();
#endif // __CINT__

template <class Element> inline const Element *TMatrixTSym<Element>::GetMatrixArray() const { return fElements; }
template <class Element> inline Element *TMatrixTSym<Element>::GetMatrixArray() { return fElements; }
Expand Down
11 changes: 11 additions & 0 deletions math/matrix/inc/TVectorT.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,17 @@ template<class Element> class TVectorT : public TObject {
ClassDef(TVectorT,4) // Template of Vector class
};

#ifndef __CINT__
// When building with -fmodules, it instantiates all pending instantiations,
// instead of delaying them until the end of the translation unit.
// We 'got away with' probably because the use and the definition of the
// explicit specialization do not occur in the same TU.
//
// In case we are building with -fmodules, we need to forward declare the
// specialization in order to compile the dictionary G__Matrix.cxx.
template <> TClass *TVectorT<double>::Class();
#endif // __CINT__

template<class Element> inline TVectorT<Element> &TVectorT<Element>::Use (Int_t n,Element *data) { return Use(0,n-1,data); }
template<class Element> inline const TVectorT<Element> &TVectorT<Element>::Use (Int_t n,const Element *data) const { return Use(0,n-1,data); }
template<class Element> inline TVectorT<Element> &TVectorT<Element>::Use (TVectorT &v)
Expand Down

0 comments on commit 5197ed6

Please sign in to comment.