AddExec in compiled code with an argument

Hi again, I’m trying to implement an AddExec in a class, which will create a TCanvas and do things when the mouse does things. I would additionally like the function which is added via AddExec to take an argument. Is that possible?

Here’s a MWE of my first attempt, which failed. The argument is an integer “num” or “my_num”. I hope it’s clear that I really don’t understand what AddExec is doing under the hood – I think there’s no way my simple int my_num = 2 declaration could’ve worked, and yet I try.

script:
http://www.cern.ch/tuna/mwe2/script.C

include:
http://www.cern.ch/tuna/mwe2/MyClass.hh

compile:
g++ -I. -fPIC -Wall -O3 -g -std=c++11 -m64 -I/usr/local/Cellar/root/6.12.04/include/root -o script.x -L/usr/local/Cellar/root/6.12.04/lib/root -lGui -lCore -lImt -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lTreePlayer -lRint -lPostscript -lMatrix -lPhysics -lMathCore -lThread -lMultiProc -lpthread -lm -ldl script.C

run:
./script.x

I get:

root [0]   gInterpreter->Declare("#include \"MyClass.hh\"");
root [1]   auto obj = new MyClass();
root [2]   obj->Run();
root [3] input_line_45:2:2: error: cannot initialize an array element of type 'void *' with an rvalue of type
      'void (*)(int)'
 MyClass::MouseEvent(my_num)
 ^~~~~~~~~~~~~~~~~~~

Hi @couet. Yes, this crashes. I was hoping you (or someone) would have a suggestion on how to make this concept work.

  gPad->AddExec("MouseEvent", Form("MyClass::MouseEvent(%d)",my_num));

Hi @couet. I’m using an integer here as an example – the thing which I actually want to pass is not an integer. It’s a std::vector, or maybe a std::map. So a string representation is not helpful.

Sorry for the confusion.

The 2nd parameter of AddExec is a command in a form of a character string … it is not C++ code.

Okay. So it is not feasible to pass an argument to a function via AddExec.

Do you know if it’s possible to declare a global variable my_num somewhere, which the function MouseEvent will then be aware of? Or does this conflict with MouseEvent needing to be static?

No, but I tried …

It seems the following works:

#ifndef MyClass_HH
#define MyClass_HH

#include <TROOT.h>
#include <TCanvas.h>

using namespace std;

int my_num ;

class MyClass {

public:
  MyClass();
  ~MyClass();
  void Run();
  static void MouseEvent();

private:
  TCanvas* m_canv;

};

inline MyClass::MyClass() {
  m_canv = 0;
}

inline MyClass::~MyClass() {}

inline void MyClass::MouseEvent() {
  cout << "MouseEvent " << my_num << endl;
}

void MyClass::Run() {

  m_canv = new TCanvas("m_canv", "m_canv", 1600, 800);
  m_canv->cd();

  my_num = 2;
  gPad->AddExec("MouseEvent", "MyClass::MouseEvent()");

}

#endif

If you have a stable address (i.e. static object), you can use:

gPad->AddExec("MouseEvent", Form("MyClass::MouseEvent(%p)",&my_num));

but then again if you have a static object, you can also use Olivier’s example.

Ooh, good suggestion. This works well. I can:

  1. declare a pointer elsewhere, e.g. vector<int>* my_num = new vector<int>()

  2. access the object in MyClass::Run, e.g. my_num->push_back(3)

  3. pass the pointer as you say, gPad->AddExec("MouseEvent", Form("MyClass::MouseEvent(%p)", my_num))

  4. Cast back into a pointer in MouseEvent, auto theptr = (vector<int>*)(num)

In summary:
http://www.cern.ch/tuna/mwe3/MyClass.hh

I don’t know if this would be considered a bastardization of pointers, but it works well for this case. Thanks!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.