TTree::Branch, which version is getting called?

Hi,

I thought that when I wrote code like:


vector<int> data;

TTree* t = new TTree( "tree", "tree_disc" );
t->Branch( "name", &data );

That I was somehow calling this function:

TBranch*	Branch(const char* name, void** obj, Int_t bufsize = 32000, Int_t splitlevel = 99)

since it is the only Branch that can be called with just two parameters (at least according to the info here: http://root.cern.ch/root/html/TTree.html#TTree:Branch%8)

Of course, this has to be wrong, since you cannot implicitly convert vector* to void**. To get to my question, what I would like to know is:

  1. what version of TTree::Branch is being called when I use the form tree->Branch( “name”, &data );

  2. (probably answered by the answer to question 1) Why do the methods that succeed in the code snippet below succeed, and why do those that fail not succeed? (I know the pointer to void pointer one looks ridiculous and wrong for other reasons.) I did receive the following errors from root:

Error in TTree::Branch: The pointer specified for voidPtr is not of a class or type known to ROOT
Error in TTree::Branch: The pointer specified for doubleVoidPtr is not of a class known to ROOT

  1. How can a ttree know how to store the actual data of an object just from a pointer? A pointer to an object only tells you the address of the object, right? Are there only specific classes root can deal with? How does it determine the type of the class from the pointer, especially if it is converting it to void*?

Thanks for any help anyone can offer.
–John


#include "TFile.h"
#include "TTree.h"
#include <vector>

using namespace std;
class Example
{
private:
	TFile* file;
	TTree* tree;
	vector<int> dog;
	int numFills;
public:
	Example(const char* filename)
	{
		// create a TFile and TTree
		file = new TFile( filename, "RECREATE", "member_file" );
		tree = new TTree( "member_tree", "member_tree_discription" );
		
		// the number of times to fill the tree
		numFills = 100000;
		
		// put some data in our vector;
		dog.push_back(1);
		dog.push_back(2);
		dog.push_back(3);
	}
	
	// create branch with branch method.
	void thisWorks()
	{
		tree->Branch("works", &dog);
		fillTree();
		
	}
	
	// create branch by passing void ptr to function.
	void thisDoesNotWork()
	{
		createBranchVoidPtr( "voidPtr", &dog );
		fillTree();
		
	}
	
	// create branch by passing vector<int>* to function.
	void butThisWorks()
	{
		createBranchTypePtr( "butThisWorks", &dog );
		fillTree();
	}
	
	// create branch by using template parameter.
	void andTheTemplateWorks()
	{
		createBranchTemplate< vector<int> >("template", &dog );
		fillTree();
	}
	
	void doubleVoidDoesNotWork()
	{
		void* dogPtr = (void*)&dog;
		createBranchVoidPtr_Ptr("doubleVoidPtr", &dogPtr );
		fillTree();
	}
	
	// fill the tree.
	void fillTree()
	{
		for( int i = 0; i < numFills; ++i )
		{
			tree->Fill();
		}
	}
	
	// void pointer data
	void createBranchVoidPtr( const char* name, void* data )
	{
		tree->Branch( name, data );
	}
	
	// typed data
	void createBranchTypePtr( const char* name, vector<int>* data )
	{
		tree->Branch( name, data );
	}
	
	// template type data
	template <class T> 
	void createBranchTemplate(const char* name, T* data )
	{
		tree->Branch( name, data );
	}
	
	void createBranchVoidPtr_Ptr(const char* name, void** data )
	{
		tree->Branch( name, data );
	}
	

	// finish up
	~Example()
	{
		tree->Print();
		file->Write();
		file->Close();
		
		
		delete file;
	}	
};


int main(int argc, char** argv)
{
	Example e1("worked.root");
	e1.thisWorks(); // creates 188K file
	
	Example e2("voidPointerFailed.root");
	e2.thisDoesNotWork(); // creates 8K file
	
	Example e3("typePointerWorked.root");
	e3.butThisWorks(); // creates 192K file
	
	Example e4("templateWorked.root");
	e4.andTheTemplateWorks(); // creates 192K file
	
	Example e5("doubleVoidFail.root");
	e5.doubleVoidDoesNotWork(); // creates 8K file

	return 0;
}
  1. Search for “template TBranch *Branch” in http://root.cern.ch/root/html/src/TTree.h.html
  2. It seems to me that you did not generate ROOT dictionary for your class (and maybe there’s a requirement that the class must inherit from TObject in these cases).
  3. See point 1 above for relevant cases, and http://root.cern.ch/root/html/TObject.html otherwise.
  1. Thank you. I wasn’t aware that you could call the template member function without providing the template type, (until I just tried it) so that explains a lot right off the bat. I wonder why these template functions are not listed here: root.cern.ch/root/html/TTree.html#TTree:Branch%8

The function that is called is:

template <class T> TBranch *Branch(const char* name, T* obj, Int_t bufsize = 32000, Int_t splitlevel = 99)
  1. I have not ever written any dictionaries, you are correct. Maybe reading about them would help me understand what is going on in this scenario. However, it seems that this is not required for some of the standard library classes (maybe there are built in dictionaries?).

  2. Looks like I have some learning to do.

I’m sure I will have more questions. Thank you for the quick response.

–John

http://root.cern.ch/download/doc/ROOTUsersGuideHTML/ch15.html
http://root.cern.ch/download/doc/ROOTUsersGuideHTML/ch07.html
http://root.cern.ch/drupal/content/adding-your-class-root-classdef
http://root.cern.ch/drupal/content/interacting-shared-libraries-rootcint
http://root.cern.ch/drupal/content/selecting-dictionary-entries-linkdefh
http://root.cern.ch/root/RootCintMan.html

[quote]I wonder why these template functions are not listed here: root.cern.ch/root/html/TTree.html#TTree:Branch%8 [/quote]The documentation is based in the CINT view of a class. Since CINT can not handle those template member function, there are not exposed to CINT (and thus not exposed to the documentation) … even more confusing and odd member function (with the void* and void**) is artificially introduced to CINT and thus exist in the documentation but not in the actual C++ code … those are the CINT implementation of the template member (and works because CINT being an interpreter even though the parameter is void * it can still tell the real type).

Cheers,
Philippe.

I see. Thanks for the information. The fact that the documentation examples often switch into using the root command line and using macros has been very confusing for me since that is not my application.

Hi,

Yes, this confusion should go away once we switch to cling (around ROOT 6).

Cheers,
Philippe.