Can't generate dictionary for std::array containing a custom class

I have a problem in creating a dictionary for an std::array containing a custom class I defined. I put together a simple reproducer (reproducer.tar.gz (700 Bytes)) so I refer to it in the following.
My code contains a MyClass, a MyArray class inheriting from std::array (originally I did this to define a custom operator, but I didn’t add these details to the reproducer), and a using directive for convenience:

using MyArrayOfMyClass = MyArray<MyClass>;

The reproducer code simply tries to write a MyArraoOfMyClass in a Root file, it can be compiled and executed with the commads:

rootcling -f Dict.cxx MyArrayOfMyClass.h LinkDef.h
g++ -o test -I`root-config --incdir` main.cpp Dict.cxx `root-config --libs`
./test

When executing test I get this error:

Warning in TStreamerInfo::Build: MyArray<MyClass>: base class array<MyClass,3> has no streamer or dictionary it will not be saved

From it I thought I had to create the dictionary for the base class array<MyClass,3>. So fine, I added this line:

#pragma link C++ class std::array<MyClass,3>+;

to the LinkDef file, but then running rootcling generates this error:

Error: It is not necessary to explicitly select class array<MyClass,3>. I/O is supported for it transparently.

So as far as I understand I am missing the dictionary for a base class but I cannot create it since it should be “transparently supported”. I’m clearly messing up things in some way, probably related to std:array, but I can’t figure out how and how to fix it, so I’d appreciate any help.
Thanks


_ROOT Version: 6.14.04
_Platform: Archlinux
_Compiler: gcc 8.2.1


It looks like the support std::array as a base class has not been implemented yet. Note that STL classes are not designed to be inherited from and the result may or may not be what you expect/need.

As a work-around instead of using inheritance you can use template aliasing or composition (in the reproducer, template aliasing is the right choice since MyArray does not add anything).

template <class T>
using MyArray = std::array<T, 3>; 

Cheers,
Philippe.

Hi Philippe, thanks for the reply. I know that STL containers have no virtual destructor so inheriting from them can generate some problems. However I won’t use the derived class polymorphically nor add any member. I just want to modify the behaviour by redefining operator[] so that it takes an enum class as argument instead of an integer. I didn’t bother to add the redefinition of operator[] in the MyArray derived class in the reproducer since it’s not relevant for the issue connected to the ROOT dictionaries.

About your suggestions: composition sounds feasible but writing N forwarding methods (with N supposedly large but unknown at this point, I really don’t know how big is the std::array interface…) just for slightly changing a single operator is something I would happily avoid. Also template aliasing is not feasible since I need to modify the operator[] and so to define a new class.

Is there any chance that the Root team would provide automatic dictionary generation for classes inheriting from std::array? If yes, should I open a bug report / feature request on JIRA?

Thanks again.

Yes, you should open a ticket.
To work around the problem you use the odd looking:

template<typename T>
class MyArray
#ifndef __CLING__
// part for regular C++ code
     : public std::array<T, 3>{
#else
// part for the I/O 
{
    std::array<T,3> fContent;
#endif
// etc.
};

With this the dictionary will be generated and the ‘fake’ member fContent will have the same offset as the base class and thus the right data will be streamed in and out.

The main downside is that you will not be able to use the std::array interface on your object from the prompt or from scripts (i.e. when parsed via Cling).

Cheers,
Philippe.

Thanks Philippe. I opened a feature request here and I will play with your workaround in the meantime. Do you feel that such a feature has a chance of being implemented?

It should eventually be implemented but we will have to discuss internally the priority/scheduling.

The workaround works as expected, however the limitation it poses on the usage from the Root shell or scripts makes it not viable for my needs. I ended up writing a class which does nothing but declaring the same interface of std::array (copy-pasted from the standard array header shipped with gcc and adapted) and forwarding all the calls to the internal std::array member. Then I inherit my custom array from this forwarder (I need to inherit several times, so that’s why I defined a reusable intermediate forwarder). Really dumb but should fully work until a proper solution is implemented in Root.
For those having the same issue, here’s the forwarder header: ArrayForwarder.h (3.3 KB)

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