I have a CMake-compiled code that creates a tree of some custom classes and saves it in a ROOT file. The code works well, and the problem appears when I try to access some compiled functions interactively with the ROOT console. I tell ROOT where my libraries/dictionaries are by adding the folder to LD_LIBRARY_PATH. It recognizes the functions well (so it is working), however, if I try to load a tree, it troubles only the branches that are std::vectors or std::maps of my custom classes.
I get this error:
Error in TChain::SetBranchAddress: Unable to determine the type given for the address for “SEL”. This is probably due to a missing dictionary, the original data class for this branch is vector<SelectionBase*>.
However the dictionary is there since I used it to create the tree the first time. I declared both structures in the LinkDef.h, and I created the dictionaries with CMake with the root_generate_dictionary command. This is my LinkDef.h:
#ifdef __CLING__
#pragma link C++ class SelectionBase+;
#pragma link C++ class vector <SelectionBase*>+;
#endif
Is there something else I must consider? I know this code used to work with some older ROOT versions, and at some point, it does not work with the newer versions.
Those the header that you pass to root_generate_dictionary includes the definition of both SelectionBase and vector (i.e. #include <vector>). Was there any error or warnings during the build?
Hi @pcanal,
Yes, inside SelectionBase.hxx, where the class SelectionBase is defined, there is an #include<vector>. There is no errors during compilation, and it executes also without errors. The problem appears when reading the generated TFiles interactively in the ROOT terminal. For some reason, it does not recognize the vectors of the declared classes. Should I generate the dictionaries in a different manner, to be able to use it in the interactive terminal?
Hi @Wile_E_Coyote ,
This is the output that I obtained. I’m not sure what I should check with this, but it looks fine.
$ root -l -q -b -e '.class SelectionBase'
===========================================================================
class SelectionBase
SIZE: 5568 FILE: SelectionBase.hxx LINE: 84
List of member variables --------------------------------------------------
SelectionBase.hxx 501 0x8 protected: Int_t _selEnabledIndex
[same for many other variables]
List of member functions :---------------------------------------------------
filename line:size busy function type and name
(compiled) (NA):(NA) 0 public: SelectionBase();
(compiled) (NA):(NA) 0 public: SelectionBase(bool forceBreak, Int_t eventBoxId = UNASSIGNEDID);
[same for many other functions]
$ root -l -q -b -e '.class std::vector<SelectionBase*>'
===========================================================================
class std::vector<class SelectionBase *, class std::allocator<class SelectionBase *> >
SIZE: 24 FILE: stl_vector.h LINE: -1
Base classes: --------------------------------------------------------
0x0 protected std::_Vector_base<class SelectionBase *, class std::allocator<class SelectionBase *> >
List of member variables --------------------------------------------------
List of member functions :---------------------------------------------------
filename line:size busy function type and name
(compiled) (NA):(NA) 0 public: vector();
(compiled) (NA):(NA) 0 public: explicit vector(const std::vector<SelectionBase *, std::allocator<SelectionBase *> >::allocator_type &__a);
[same for other functions]
Hi @Wile_E_Coyote, thank you very much for your help. I see your point. If I do your test, I don’t get any errors and I’m able to recover the info in the tree interactively. So the problem I think is in the way the branch is declared in the compiled functions.
It is declared in this way since the branches are declared in a general function, used to set many types of branches. I still don’t see why this way is wrong, and I know this code used to work in old root versions.
There are several potential solution. Wile’s last post is a one solution. Another, probably better, solution is to make you generic routine function template based on the actual type (For example, this is done for SetBranchAddress itself).
TTree records the address of the variable _pointer and will use (and update) its value. After the initilization:
_pointer=v;
_pointer and v are completely disconnected and v is never change nor used by TTree.
Wile’s solution works as it records and passes the address of the variable v (instead of the value in your example).
Error in <TTree::SetBranchAddress>: Unable to determine the type given for the address for "SEL". This is probably due to a missing dictionary, the original data class for this branch is vector<SelectionBase*>.
About the template function proposed by @pcanal, it sounds reasonable, but this might imply many modifications in the code (I believe, since I’m not sure of how to do such a change).