ROOT missing TClass for 'int', do I really have to make a dictionary for it?

I had expected ROOT to come with TClass for basic types and to be able to create a TBranch for int, long and also typedefs of them like size_t without having to do anything…

My version apparently does not support this (6.34.06 rpm for Almalinux 9, gcc 11.5 every root-* rpm is installed):

root [0] TTree *mytree = new TTree();
root [1] int i;
root [2] int* pi = &i;
root [3] mytree->Branch("myint", "int", &pi);
Error in <TTree::Bronch>: Cannot find class:int
root [4] mytree->Branch("myint", &pi);
Error in <TTree::Branch>: The pointer specified for myint is not of a class known to ROOT
root [5] TClass::GetClass("int")
(TClass *) nullptr
root [6] TClass::GetClass<int>()
(TClass *) nullptr
root [7] TClass::GetClass(typeid(int))
(TClass *) nullptr

Note that, on the other hand, string and vector are there…

root [8] TClass::GetClass("std::string")
(TClass *) 0x563341763b60
...
root [12] TClass::GetClass("std::vector<int>")
(TClass *) 0x563341766200

and I can also use struct types for which I have generated dictionaries, no problems there.

I’m not sure if this is a bug or intended behavior, as I cannot find documentation stating which types come predefined. If it is intended, how do I make a dictionary for ‘int’?

#pragma link C++ class int;
results in
Warning: Unused class rule: int

C++ built-in fundamental types are not classes.
Try:
mytree->Branch("myint", &i);
mytree->Branch("myint", pi);

Hello, thanks for your reply. Unfortunately it does not solve my problem.

@pcanal I am aware of the, in my opinion unfortunate, distinction in the c++ standard between types and classes. I was hoping ROOT would attempt to hide it. Are you saying that it is instead impossible for TClass to represent native types and/or to generate dictionaries for them?

Being unable to use the same function for a native type and a class breaks a symmetry, if you wish…
In my application framework I handle a multitude of user defined types, and I no longer have access to the actual type at the point of calling Branch.

I was therefore using the Branch(const char* name, const char* classname, void* addobj, …) overload, which however does not work when one of my users decides their user-defined-type is just a typedef for int.

Is there an overload of Branch that would work for both under my use case? My understanding at this point is no.

If not, I have to exclude native types or force them to be wrapped in a class, which is quite inconvenient.

You can use for objects (assuming the class is “known to ROOT”, i.e., with a dictionary):
Branch("branchname", &object)
The same way as for fundamental types:
Branch("branchname", &variable)

There is no need to generate dictionary for them. They are either already fully supported or not supported at all (eg. long double).

Are you saying that it is instead impossible for TClass to represent native types

For better or worse, the existing design make a distinction between the 2 categories (and really in term of I/O the 2 categories are handled very differently).

If you want a class that represent a native type, you can use the existing wrapper template <typename T> TParameter;

In term of getting run-time information for C++ entities there is multiple access point. TClass inherits from TDictionary are represent classes and namespace. For native type and typedef there is TDataType that also inherits from TDictionary.

Is there an overload of Branch that would work for both under my use case? My understanding at this point is no.

You can do something like this:

auto cl = TClass::GetClass(typeid(T));
if (cl) {
   tree->Branch(branchname, cl->GetName(), ....);
} else {
   auto datatype = TDataType::GetType(typeid(T));
   if (datatype == kOther_t || datatype == kNoType_t) {
         Error("Branch", "The pointer specified for %s is not of a class or type known to ROOT", branchname);
      } else {
         TString varname; varname.Form("%s/%c", branchname, DataTypeToChar(datatype));
          tree->Branch(branchname,addobj,varname.Data(),bufsize);
      }
   }
}

(where you would need to copy/paste the code for DataTypeToChar from TTree.cxx or use RDF’s ROOT::Internal::RDF::TypeName2ROOTTypeName

1 Like

Thank you for your suggestions, I had completely missed the existence of TDataType. I think this solves my problem