The task at hand is to evaluate a function that is only known at run time with help of ROOT.
The below example can be called with ./main "return 1000*a + b;"
and it creates a lambda [](int a, int b) { return 1000*a + b; }
and calls it with arguments 42, 23.
#include "TInterpreter.h"
#include "TInterpreterValue.h"
#include <functional>
#include <iostream>
// inspired from https://stackoverflow.com/a/28747100
class Functor {
using FuncType = std::function<int(int, int)>;
FuncType m_f;
public:
Functor(FuncType f) : m_f{std::move(f)} {}
int operator()(int a, int b) { return m_f(a, b); }
};
int main(int argc, char **argv) {
Functor *runtime_functor(nullptr);
Functor *compiletime_functor(nullptr);
TInterpreterValue *tiv = gInterpreter->CreateTemporary();
// yes, I let that leak but don't care for the sake of this example
compiletime_functor = new Functor([](int a, int b) { return a + b; });
std::string expr("Functor([](int a, int b) {");
expr += argv[1];
expr += "})";
// TODO: put this into a header
gInterpreter->Declare("class Functor { "
" using FuncType = std::function<int(int, int)>; "
" FuncType m_f; "
" "
"public: "
" Functor(FuncType f) : m_f{std::move(f)} {} "
" "
" int operator()(int a, int b) { return m_f(a, b); } "
"}; ");
std::cout << "evaluating lambda: " << expr << std::endl;
gInterpreter->Evaluate(expr.c_str(), *tiv);
runtime_functor = (Functor *)tiv->GetAsPointer();
std::cout << "evaluating compiletime lambda with arguments 42, 23"
<< std::endl;
std::cout << (*compiletime_functor)(42, 23) << std::endl;
std::cout << "evaluating runtime lambda with arguments 42, 23" << std::endl;
std::cout << (*runtime_functor)(42, 23) << std::endl;
return 0;
}
This code works okay, but I realised that the Evaluate
call does not lead to diagnostics:
./main "
int k;
return k;"
This would normally with g++ lead to the warning warning: ‘k’ is used uninitialized in this function [-Wuninitialized]
but doesn’t here with the gInterpreter
.
I saw I can set the include paths for the gInterpreter
with gInterpreter->AddIncludePath(...)
and inspect its content with GetIncludePath
. But I’m wondering, can I set other compiler options like warnings, optimisations, or other -f -m settings for the gInterpreter
? (Maybe as background info: does Evaluate
actually lead to compilation by cling?)
side note: For similar’ish use cases I used gInterpreter->LoadMacro(filename.cpp+O)
and steered the behaviour with gSystem->SetFlagsOpt
but would like to avoid the boiler plate of creating and cleaning up temporary files.
PPS: this is an MWE for https://gitlab.cern.ch/lhcb/LHCb/merge_requests/1302