Hello Philippe,
Thank you so much for the help. I was able to get a version of it to work using std::get, which is nice.
If I may ask a follow-up question, I have since been trying to make my “branch holder” object handle all kinds of access to the underlying branch variable. My goal is to make it very easy for others to add a branch to my ntuplizer, such that they only need to specify the branch TString and the default value to be set for every event, with the appropriate literal type (e.g. ul, .f, L, etc). I have something like this:
std::map<TString, BranchInfo> branches({
{"run", BranchInfo{-1}},
{"event", BranchInfo{-1}},
{"ls", BranchInfo{-1}},
{"pv_x", BranchInfo{-99.}},
{"pv_y", BranchInfo{-99.}},
{"pv_z", BranchInfo{-99.}},
{"nVertices", BranchInfo{0u}
});
In BranchInfo I then have overloaded the () and = operators to allow access to some branches more directly:
using AllTypes = std::variant<bool, int, float, double, unsigned int, long unsigned int, long long unsigned
int, std::vector<float>, std::vector<int>, std::vector<TString>>;
BranchInfo& operator= (AllTypes val) { value = val; return * this; }
double operator() () {
using T = std::decay_t<decltype(value)>;
if (std::holds_alternative<bool>(value))
return static_cast<double>(std::get<bool>(value));
else if (std::holds_alternative<int>(value))
return static_cast<double>(std::get<int>(value));
else if (std::holds_alternative<float>(value))
return static_cast<double>(std::get<float>(value));
else if (std::holds_alternative<double>(value))
return static_cast<double>(std::get<double>(value));
else if (std::holds_alternative<unsigned int>(value))
return static_cast<double>(std::get<unsigned int>(value));
else if (std::holds_alternative<long unsigned int>(value))
return static_cast<double>(std::get<long unsigned int>(value));
else if (std::holds_alternative<long long unsigned int>(value))
return static_cast<double>(std::get<long long unsigned int>(value));
else if (std::holds_alternative<std::vector<int>>(value))
std::cout << "Error this type is vector int " << std::endl;
// static_assert(always_false_v<T>, "Don't know how to use vector!");
else if (std::holds_alternative<std::vector<float>>(value))
std::cout << "Error this type is vector float " << std::endl;
// static_assert(always_false_v<T>, "Don't know how to use vector!");
else if (std::holds_alternative<std::vector<TString>>(value))
std::cout << "Error this type is vector TString " << std::endl;
// static_assert(always_false_v<T>, "Don't know how to use vector!");
else
std::cout << "Error this type is unknown" << std::endl;
// static_assert(always_false_v<T>, "Don't know this type!");
return -9999.;
}
So I can for example use the assign operator to set a value during the event analyzer:
branches["nVertices"] = 40;
and I can also convert all scalar (non-vector) quantities to double to read them if needed:
std::cout << "Event number: " << branches["event"]() << std::endl;
But what I would really like to do is to be able to access e.g. std::vectors more directly, so for example over the course of the analysis of an event I could just push_back to such a vector, and BranchInfo would automatically understand which variant specialization I’m talking about. However, I haven’t really found a way to do that. I think it should be possible since I am already specifying the type of every branch at compile time, but I can’t for example overload an operator with different return types only. I think I might be able to use some template magic to do that, but I’m not sure how.
Hopefully the question was clear enough, and any pointers will be greatly appreciated.
Cheers.
Andre