How to use ClassDefInline?

Hello,

According to https://sft.its.cern.ch/jira/browse/ROOT-8784 ClassDefInline should make it possible to bypass the situation where “one of the template instances can not have its dictionary generated (for example some members are references) but other template instance needs to have their dictionary generated”.

I am trying to use ClassDefInline (in non-interactive mode) to avoid having to IO a template instance where the members are references, but I get that fgIsA cannot be found. Manually adding static atomic_TClass_ptr fgIsA; to my private data members solves this, but then I get a bunch of error: uninitialized reference member <reference_member> which I got using the normal ClassDef as well…

What I had done up til now to take care of reference members was to expand the ClassDef macro in my class’ header file, default initialize some of its functions, and delete the LinkDef entry of the reference template instance. This works fine, but is kind of ugly.

I had hoped `ClassDefInline`` would be a more elegant solution. So I hope someone could tell me how to use it.

Hi,

Yes, ClassDefInline should have worked for you. Which version of ROOT are you using? When is the error appearing? What is the complete error message?

Cheers,
Philippe.

I’m using ROOT v6.10.00. The error appears at compile time with error messages such as the following:

In file included from /home/ahmad/biodynamo/src/resource_manager.h:4:0,
                 from /home/ahmad/biodynamo/demo/cell_division_module.h:5,
                 from /home/ahmad/biodynamo/demo/cell_division_module.cc:1:
/home/ahmad/biodynamo/src/cell.h: In instantiation of ‘bdm::CellExt<Base, TBiologyModuleVariant>::CellExt() [with Base = bdm::SimulationObject<bdm::SoaRef>; TBiologyModuleVariant = mpark::variant<bdm::GrowthModule>]’:
/home/ahmad/root/include/Rtypes.h:228:44:   required from ‘static void* ROOT::Internal::ClassDefGenerateInitInstanceLocalInjector<T>::New(void*) [with T = bdm::CellExt<bdm::SimulationObject<bdm::SoaRef>, mpark::variant<bdm::GrowthModule> >]’
/home/ahmad/root/include/Rtypes.h:241:35:   required from ‘static ROOT::TGenericClassInfo* ROOT::Internal::ClassDefGenerateInitInstanceLocalInjector<T>::GenerateInitInstanceLocal() [with T = bdm::CellExt<bdm::SimulationObject<bdm::SoaRef>, mpark::variant<bdm::GrowthModule> >]’
/home/ahmad/root/include/Rtypes.h:244:70:   required from ‘static TClass* ROOT::Internal::ClassDefGenerateInitInstanceLocalInjector<T>::Dictionary() [with T = bdm::CellExt<bdm::SimulationObject<bdm::SoaRef>, mpark::variant<bdm::GrowthModule> >]’
/home/ahmad/root/include/Rtypes.h:245:48:   required from ‘static TClass* ROOT::Internal::ClassDefGenerateInitInstanceLocalInjector<T>::Class() [with T = bdm::CellExt<bdm::SimulationObject<bdm::SoaRef>, mpark::variant<bdm::GrowthModule> >]’
/home/ahmad/biodynamo/src/cell.h:262:3:   required from ‘static TClass* bdm::CellExt<Base, TBiologyModuleVariant>::Class() [with Base = bdm::SimulationObject<bdm::SoaRef>; TBiologyModuleVariant = mpark::variant<bdm::GrowthModule>]’
/home/ahmad/biodynamo/src/cell.h:262:3:   required from ‘TClass* bdm::CellExt<Base, TBiologyModuleVariant>::IsA() const [with Base = bdm::SimulationObject<bdm::SoaRef>; TBiologyModuleVariant = mpark::variant<bdm::GrowthModule>]’
/home/ahmad/biodynamo/demo/cell_division_module.cc:47:31:   required from here
/home/ahmad/biodynamo/src/cell.h:67:3: error: uninitialized reference member in ‘bdm::CellExt<bdm::SimulationObject<bdm::SoaRef>, mpark::variant<bdm::GrowthModule> >::vec<std::array<double, 3ul> > {aka class std::vector<std::array<double, 3ul>, std::allocator<std::array<double, 3ul> > >&}’ [-fpermissive]
   CellExt() {}
   ^
/home/ahmad/biodynamo/src/cell.h:239:25: note: ‘std::vector<std::array<double, 3ul>, std::allocator<std::array<double, 3ul> > >& bdm::CellExt<bdm::SimulationObject<bdm::SoaRef>, mpark::variant<bdm::GrowthModule> >::position_’ should be initialized
   vec<array<double, 3>> position_;

I don’t see where the error message mentions fgIsA …

On the other hand I see that the Default constructor must be set to be deleted as it can not be instantiated/realized in this case …

I don’t see where the error message mentions fgIsA …

Right, that’s because I added it as a private data member myself. If I wouldn’t do that I would get:

/home/ahmad/biodynamo/build/bdmDict.cxx: In static member function ‘static TClass* bdm::CellExt<Base, TBiologyModuleVariant>::Dictionary() [with Base = bdm::SimulationObject<bdm::Soa>; TBiologyModuleVariant = mpark::variant<bdm::NullBiologyModule>]’:
/home/ahmad/biodynamo/build/bdmDict.cxx:1598:4: error: ‘fgIsA’ was not declared in this scope
    fgIsA = ::ROOT::GenerateInitInstanceLocal((const ::bdm::CellExt<bdm::SimulationObject<bdm::Soa>,mpark::variant<bdm::NullBiologyModule> >*)0x0)->GetClass();

Making the default constructor deleted creates a problem for the non-reference template instances. It leads to the following error:

/home/ahmad/root/include/Rtypes.h:230:28: error: call to deleted constructor of 'bdm::CellExt<bdm::SimulationObject<bdm::Soa>, mpark::variant<bdm::NullBiologyModule> >'
         return p ? new(p) T[nElements] : new T[nElements]; }

The fgIsA problem is per se described in https://sft.its.cern.ch/jira/browse/ROOT-8784 which is not fixed yet.

I.e. at the moment if you use ClassDefInline, you can not request the dictionary.

To solve this problem with you current version of ROOT you need to have a partial specialization of your template:

template <typename T, typename Q> class CellExt<T&,Q> {
CellExt() = delete;
...
};

Unfortunately the situation is a little more complicated to solve this problem with partial specialization (at least to my knowledge). The CellExt<T, Q> class takes for T one of the three predefined structs, of which one is defined as the following:

struct SoaRef {
  template <typename T>
  using vec = std::vector<T>&;
  ...(more stuff)
};

This is the template argument that is giving me the uninitialized reference members errors as show in the third post. The vec data members in CellExt will namely become references, which will not be initialized (and don’t need to be initialized) when ROOT creates the IO methods, hence the error messages.

But partial specialization (even if it would work) would seem like a less elegant way then to just do the ClassDef expansion I mentioned earlier. I had hoped ClassDefInline could just ignore the reference-containing struct as the template parameter argument when generating the IO methods.

Humm … if that the case, it seems even more simple :slight_smile:

template <typename Q> class CellExt<SoaRef,Q> {
CellExt() = delete;
...
};

Cheers,
Philippe.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.