I suspect there are good reasons to delete the iterators in python/template/macros/iterator/iterator.jinja2, but it makes searching through a collection a bit more cumbersome at times. I am wondering if there are ways in which some of the choices on iterator copy constructors and assignment operators deletion can be relaxed, or am I missing something I should be using instead?
The following are attempts at finding the first electron in an MCParticlesCollection. I am using gcc-11 with -std=gnu++20.
Using find_if to get an iterator to the first electron
const auto mc_first_electron = std::find_if(
mcparts.begin(),
mcparts.end(),
[](const auto& p){ return p.getPDG() == 11; });
This fails because MCParticleCollectionIterator has a deleted copy constructor which is required (likely) to return a copy of the internal iterator inside std::find_if.
Using a simple (old-style) iterator loop
If we can't copy an iterator, then let's avoid the copy.
auto mc_first_electron = mcparts.end();
for (auto p = mcparts.begin(); p != mcparts.end(); p++) {
if (p->getPDG() == 11) {
mc_first_electron = p;
break;
}
}
This fails because iterator post-increment is not implemented. Ok, easy enough to change (and arguably better though unlikely that an iterator takes up so much memory this matters here; still, it is good to instill best practices).
auto mc_first_electron = mcparts.end();
for (auto p = mcparts.begin(); p != mcparts.end(); ++p) {
if (p->getPDG() == 11) {
mc_first_electron = p;
break;
}
}
This still fails but now because we cannot assign p to mc_first_electron since the assignment operator for iterators is deleted. Ok, we can avoid this assignment too, by avoiding a locally scoped iterator.
auto mc_first_electron = mcparts.begin();
for (; mc_first_electron != mcparts.end(); ++mc_first_electron) {
if (mc_first_electron->getPDG() == 11) {
break;
}
}
Ah, we have something that compiles.
Checking that we actually found something
After the search, we want to make sure we found something (and return if not).
if (mc_first_electron == mcparts.end()) {
debug() << "No electron found" << endmsg;
return StatusCode::FAILURE;
}
This now fails again because operator== isn't defined for iterators. We already used operator!= above, so we end up with this:
if (!(mc_first_electron != mcparts.end())) {
debug() << "No electron found" << endmsg;
return StatusCode::FAILURE;
}
Ultimately, in a c++20 world,...
When I started off, I had hopes of being able to use the following compact syntax:
auto is_electron = [](const auto& p){ return p.getPDG() == 11; };
for (const auto& e: mcparts | std::views::filter(is_electron)) {
// stuff
}
This does not compile (unsurprisingly) due to the missing operator| on collections. Implementing this doesn't seem too onerous but I think I'd need to understand first what the design decisions were for the deleted iterators and assignment operators.
I suspect there are good reasons to delete the iterators in python/template/macros/iterator/iterator.jinja2, but it makes searching through a collection a bit more cumbersome at times. I am wondering if there are ways in which some of the choices on iterator copy constructors and assignment operators deletion can be relaxed, or am I missing something I should be using instead?
The following are attempts at finding the first electron in an MCParticlesCollection. I am using gcc-11 with
-std=gnu++20.Using
find_ifto get an iterator to the first electronThis fails because MCParticleCollectionIterator has a deleted copy constructor which is required (likely) to return a copy of the internal iterator inside std::find_if.
Using a simple (old-style) iterator loop
If we can't copy an iterator, then let's avoid the copy.
This fails because iterator post-increment is not implemented. Ok, easy enough to change (and arguably better though unlikely that an iterator takes up so much memory this matters here; still, it is good to instill best practices).
This still fails but now because we cannot assign p to mc_first_electron since the assignment operator for iterators is deleted. Ok, we can avoid this assignment too, by avoiding a locally scoped iterator.
Ah, we have something that compiles.
Checking that we actually found something
After the search, we want to make sure we found something (and return if not).
This now fails again because operator== isn't defined for iterators. We already used operator!= above, so we end up with this:
Ultimately, in a c++20 world,...
When I started off, I had hopes of being able to use the following compact syntax:
This does not compile (unsurprisingly) due to the missing operator| on collections. Implementing this doesn't seem too onerous but I think I'd need to understand first what the design decisions were for the deleted iterators and assignment operators.