ROOT の macro で定義した関数の返り値を受け取る方法

RootTalk で教えてもらったのでメモ。

例えば MyScript.C というのがあったとして、この中に MyFunc() という関数があったとします。

MyClass MyFunc()
{
  return MyClass();
}

そして、この MyScript.C を CINT に読み込みます。

int main()
{
(略)
  gROOT->LoadMacro("MyMacro.C++");
(略)
}

こうすると、CINT や RINT の中では MyFunc() を呼び出せるのですが、上記の main の中でどうやって返り値を取り出せば良いのか悩みどころです。そこで、ちょっとややこしいことをすると取りだせるようになります。基本的なやり方は以下の通りです。

int main()
{
(略)
  gROOT->LoadMacro("MyMacro.C++");
  MyClass ret; 
  gInterpreter->ProcessLine(Form("*(MyClass*)%p = MyFunc();", (void*)&ret));
(略)
}

言われてみると結構単純な考え方です。

もう少し具体例で考えます。TVector3 もしくは TVector3* を返す関数があったとして、これを MyMacro.C に定義します。

#include "TVector3.h"

TVector3 MyFunc1()
{
  return TVector3(1, 2, 3);
}

TVector3* MyFunc2()
{
  return new TVector3(10, 20, 30);
}

これを、main() の中で呼びだします。TVector3* を受け取るためには、pointer の pointer を使わないといけないので注意が必要です。

int main()
{
(略)
  gROOT->LoadMacro("MyMacro.C++");
  TVector3 v1;
  TVector3* v2;

  gInterpreter->ProcessLine(Form("*(TVector3*)%p = MyFunc1();", (void*)&v1));
  v1.Print();
                            
  gInterpreter->ProcessLine(Form("*(TVector3**)%p = MyFunc2();", (void*)&v2));
  v2->Print();
(略)
}

なんでこんな事をやる必要が出たかというと、何かの計算をするときの設定を ROOT macro 内で定義できないかと検討したためです。光線追跡をするときに、普通だったら望遠鏡の形状を text 形式で定義しておき、それを読み込んだりします。ただし、設定を読むための関数を書くのが面倒。そこで、望遠鏡の定義は ROOT の geometry で .C の中に書いておき共通の interface だけ持たせ、それを main の中で読み込めば挙動を変えられるのではないか、という発想です。