Adding a class: namespace, std::vector, mutual dependencies

Hello,

I am trying to create a dictionary and compile a static library libMyTest.a with classes A, B, and C in namespace MyTest. The library is linked against when compiling the executable MyTest from main.cxx. All files are attached in a zip file as well as a compile script containing the required bash commands. The code is also included below in this post.

MyTest::A and MyTest::B are mutually dependent and have to know about each other. MyTest::A has a std:vector as class member. So far, so good, with the help of the ROOT User’s guide and various posts on this forum I have been able to solve a lot of issues.

However, trouble starts again when I try to add to MyTest::A a member function
DoStuffWithBVector( std:vector vectorOfBs) that uses a std:vectorMyTest::B as parameter. Then all of a sudden the good old errors return when linking the library:

MyTestDict.cxx: In function ‘int G__MyTestDict_169_0_2(G__value*, const char*,
G__param*, int)’:
MyTestDict.cxx:554:73: error: ‘B’ was not declared in this scope
       ((MyTest::A*) G__getstructoffset())->DoStuffWithBVector(*((vector<B>*)
       G__int(libp->para[0])));
                                                                         ^
MyTestDict.cxx:554:73: note: suggested alternative:
In file included from MyTestDict.h:34:0,
                 from MyTestDict.cxx:17:
B.h:10:7: note:   ‘MyTest::B’
 class B : public TObject
       ^
MyTestDict.cxx:554:74: error: template argument 1 is invalid
       ((MyTest::A*) G__getstructoffset())->DoStuffWithBVector(*((vector<B>*)
       G__int(libp->para[0])));
                                                                          ^
MyTestDict.cxx:554:74: error: template argument 2 is invalid
MyTestDict.cxx:554:76: error: expected primary-expression before ‘)’ token
       ((MyTest::A*) G__getstructoffset())->DoStuffWithBVector(*((vector<B>*)
       G__int(libp->para[0])));
                                                                            ^
MyTestDict.cxx:554:78: error: expected ‘)’ before ‘G__int’
       ((MyTest::A*) G__getstructoffset())->DoStuffWithBVector(*((vector<B>*)
       G__int(libp->para[0])));

If function DoStuffWithBVector is commented out, everything works again and e.g. the constructor of A can handle a vector just fine.

Does anybodyknow what I am missing or doing wrong here???

MyTestLinkDef.h

#ifdef __CINT__

#pragma link off all class;
#pragma link off all function;
#pragma link off all global;
#pragma link off all typedef;

#pragma link C++ nestedclass;
#pragma link C++ nestedtypedef;

#pragma link C++ namespace MyTest;
#pragma link C++ defined_in namespace MyTest;

#pragma link C++ class MyTest::B+;
#pragma link C++ class std::vector< MyTest::B >+;
#pragma link C++ class MyTest::A+;
#pragma link C++ class MyTest::C+;

#endif

A.h

#ifndef A_H_
#define A_H_

#include <iostream>
#include <vector>
#include <TObject.h>

namespace MyTest

{
class B;	// include B.h in implementation file to avoid problems with mutual dependencies

class A : public TObject
{
public:
	std::vector<B>	fBVec;	// List of Bs owned by this A

	A(UInt_t numberOfBs = 0);
	~A(){}

	void DoStuffWithBVector( std::vector<B> vectorOfBs );

	ClassDef(A,1); // My class A in my MyTest namespace
};

};	// end of namespace MyTest

#endif // end of A_H_

A.cxx

#include "A.h"
#include "B.h"

ClassImp(MyTest::A)

namespace MyTest
{

	A::A(UInt_t numberOfBs) : TObject()
	{
		for(UInt_t i = 0; i < numberOfBs; i++)
		{
			B b(this,fBVec.size()-1);
			fBVec.push_back(b);
		}
	}

	void A::DoStuffWithBVector( std::vector<B> vectorOfBs )
	{
		for(UInt_t i = 0; i < vectorOfBs.size(); i++) std::cout << i << "\t" << vectorOfBs[i].fA << std::endl;
	}

};	// end of namespace MyTest

B.h

#ifndef B_H_
#define B_H_

#include "TObject.h"

namespace MyTest
{
class A;	// include A.h in implementation file to avoid problems with mutual dependencies

class B : public TObject
{
public:
	A		*fA;
	Int_t	fID;

	B(A *a = 0, Int_t id = -1);
	~B() {}

	ClassDef(B,1); // My class B in my MyTest namespace
};

};	// end of namespace MyTest

#endif // end of B_H_

B.cxx

#include "B.h"
#include "A.h"

ClassImp(MyTest::B)

namespace MyTest
{

	B::B(A *a, Int_t id) : TObject()
	{
		fA  = a;
		fID = id;
	}

};	// end of namespace MyTest

MyTest.h

#ifndef MYTEST_H_
#define MYTEST_H_

#include <vector>
#include "B.h"
#include "A.h"

namespace MyTest
{

class C : public TObject
{
protected:
	A	*fA;

public:
	C(UInt_t numberOfBsInA = 0);
	~C();

	A *GetA();

	ClassDef(C,1); // My class C in my MyTest namespace
};

};	// end of namespace MyTest

#endif // end of MYTEST_H_

MyTest.cxx

#include "MyTest.h"

ClassImp(MyTest::C);

namespace MyTest
{

	C::C(UInt_t numberOfBsInA)
	{
		fA = new A(numberOfBsInA);
	}

	C::~C()
	{
		delete fA;
	}

	A *C::GetA()
	{
		return fA;
	}

};	// end of namespace MyTest

main.cxx

#include <iostream>
#include <../TestProject/MyTest.h>

int main(int argc, char **argv) {

	MyTest::C *c = new MyTest::C(10);
	std::cout << "MyTest::C *c = " << c << "\t\tc->fBVec.size() = " << c->GetA()->fBVec.size() << std::endl;

	return 0;
}

compile.sh

#!/bin/bash

ProjectName=MyTest

# clean up
rm -f ${ProjectName} *Dict* *o *a *~

# generate dictionary
#rootcint -f ${ProjectName}Dict.cxx -c -p ${ProjectName}.h ${ProjectName}LinkDef.h
rootcint -f ${ProjectName}Dict.cxx -c -p B.h A.h ${ProjectName}.h ${ProjectName}LinkDef.h

# compile library
`root-config --cxx --cflags` -W -Wall -fPIC -c B.cxx A.cxx ${ProjectName}.cxx
#`root-config --cxx --cflags` -W -Wall -fPIC -c B.cxx A.cxx ${ProjectName}Dict.cxx ${ProjectName}.cxx

# static library
ar rvs lib${ProjectName}.a *.o

# shared library
#`root-config --cxx --cflags` -W -Wall -fPIC -shared -o lib${ProjectName}.so *.o `root-config --glibs`

# compile executable using library and dictionary
`root-config --cxx --cflags` -W -Wall -fPIC -o ${ProjectName} main.cxx ${ProjectName}Dict.cxx `root-config --cflags --glibs` -L. -l${ProjectName}

# compile executable using library without dictionary
#`root-config --cxx --cflags` -W -Wall -fPIC -o ${ProjectName} main.cxx `root-config --cflags --glibs` -L. -l${ProjectName}

MyTest.zip (3.17 KB)

Addendum: Apparently, I can hide the function from cint like this

#ifndef __CINT__ void DoStuffWithBVector( std::vector<B> vectorOfBs ); #endif
But how do I solve the problem if that’s no option?