Trouble with std::complex<double> I/O

Hi all-

 I've been having trouble with getting a class with a std::complex<double> member to properly serialize.  I've been searching all the documentation and the forums and I can't find a solution, but I think I may be doing something wrong.  

This is with ROOT 5.26.00 on a linux x86_64, though I have seen similar issues on mac os x, ppc, with ROOT 5.24.00.

I have a class with a std::complex member:

Test.hh:
#include “TObject.h”
#include
#include

#ifndef Test_hh
#define Test_hh

class Test: public TObject
{
public:

std::complex<double> fMyComplexVector;

ClassDef(Test, 0);
};
#endif /* Test_hh */

Test.cc:
#include “Test.hh”
ClassImp(Test)

Now when I load the shared library associated with this class and try to write it to disk, I get different errors depending upon my LinkDef.h

---------First error----------
LinkDef.h:
#ifdef CINT
#pragma link C++ class Test+;
#endif

Script, test.C:
{
gSystem.Load(“libtest.so”);
aTest = new Test();
temp_file = new TFile(“temp.root”, “recreate”);
aTest->Write(“test”);
temp_file->Close();
}
yields:
Error in TClass::BuildRealData: Cannot find any ShowMembers function for complex!

Initially, I thought this was because I wasn’t building a dictionary with I/O enabled for std::complex (but I thought this was already precompiled?) which lead me to my second error:

---------Second error----------
LinkDef.h:
#ifdef CINT
#pragma link C++ class std::complex+;
#pragma link C++ class Test+;
#endif

Building this yields the warning:
Note: Link requested for already precompiled class complex (ignore this message) :0:

which I initially ignored as it said :wink:, but then running the same test script as above yielded:

Processing test.C…
Fatal: sizeof(::complex) == sizeof(::ROOT::Shadow::complexlEdoublegR) violated at line 61 of `testDICT.C’
aborting

Followed by a stack trace initiated by the assert.

Two questions:

  1. Am I doing something wrong in my LinkDef.h, or perhaps do I need to generate a custom ShowMembers?
  2. If not, and this is a current limitation in rootcint, is there a workaround? I.e. can I somehow wrap std::complex to use ROOT I/O with it?

I’ve included a test suite here that will compile the test code and run the test script automatically:

Just untar and type make. To generate the different issues, the included LinkDef.h can be modified.

Thanks, and I hope everyone is having a great holiday!

Mike
test.tar.gz (1.16 KB)

Hi,

Indeed the I/O for std::complex was not supported. I just implemented it today in revision 32094 of the trunk.

Also note that in order to enable I/O for your class you will need to replace ClassDef(Test, 0); which explicit request NO I/O for that class with ClassDef(Test, 1);

Cheers,
Philippe.

Hi Philippe,

Thanks, that sounds great. As a workaround, I had already written a custom streamer to work with this, but we will revert to an automatically generated streamer once the release comes out.

[quote]Also note that in order to enable I/O for your class you will need to replace
Code:
ClassDef(Test, 0);
which explicit request NO I/O for that class with[/quote]

Indeed, sorry, I must have inadvertently left this in the test code.

Thanks!

Mike

Hi Philippe,

very nice to see that std::complex is now supported in ROOT I/O. However, while trying to use this new feature to create trees with leaf classes that have std::complex member variables, I ran into a problem: My macro which writes and reads the tree does not work, if I compile it with ACLiC. In this case all complex member variables that are read back from the tree have zero value (in contrast to e.g. double members). If I run the same macro without compilation everything works just fine.

To illustrate this problem I took the liberty of slightly modifying Mike’s code from the post above. This reproduces the above behavior using the latest ROOT developer release 5.27/06.

Maybe I’m doing something wrong. Any help would be appreciated.

Thanks a lot,
Boris.
test2.tgz (1.45 KB)

Hi,

Since the dictionary for complex is part of the built-in dictionary, attempting to generate the dictionary again has unintended consequence (here namely, it makes root believes std::complex is empty and prevents the autoloading of the correct dictionary). To solve the problem simple use the following LinkDef.h:#ifdef __CINT__ //#pragma link C++ class std::complex<double>+; //#pragma link C++ class std::vector<std::complex<double> >+; #pragma link C++ class Test+; #endif

Cheers,
Philippe.

Hi Philippe,

many thanks for providing a solution so quickly. Unfortunately I bumped into another problem that is probably related: I converted the ROOT macro into a standalone program which is linked against the shared library that also contains the dictionary for the object used as TTree leaf (see attachment). However, running this program, it complains about a missing dictionary for complex:

Warning in <TClass::TClass>: no dictionary for class complex<double> is available
Warning in <TStreamerInfo::Build:>: Test: complex<double> has no streamer or dictionary, data member "fMyComplex" will not be saved

How can I make the program aware of the complex dictionary?

Thanks for bearing with me,
Boris.
test3.tgz (1.58 KB)

Hi,

You need to force the standalone program to load the dictionary. This can be achieve by adding to you main:gROOT->ProcessLine("#include <complex>");

Cheers,
Philippe.

Hi Philippe,

thanks a lot for your reply. This indeed solves my problem. Just out of curiosity: What determines, whether I have to force the loading of the dictionary in the described way? A std::vector member variable, for example, works fine without a gROOT->ProcessLine("#include ") statement.

Thanks again,
Boris.

Hi,

The ProcessLine call is only needed to work around a bug in the library autoloading setting affecting only the std::complex classes (This is fixed in the trunk, revision 36617 and up).

Cheers,
Philippe.

Ah, okay. Thanks for the information.

Ciao,
Boris.