Python has with statements as resources managers or context managers.
In C++ RAII would take care of this.
A simple examples looks like this:
struct Resource {
Resource() { /* set up */
}
~Resource() { /* tear down */ }
};
try {
[[maybe_unused]]
auto unused = Resource();
}catch(...){}
I found it a little annoying to need a variable.
A first idea involved a macro:
#define with(resource) if ([[maybe_unused]] auto unused = resource;
true)
with(Resource()) {
spdlog::info("after init");
}
Cute. But limited.
And clang tidy informs, that there may be a better alternative.
So I tried and found this little cutie:
template<typename... ResourceTypes>
constexpr auto with(ResourceTypes &&... resources) {
return
[&resources...](
std::function<auto(ResourceTypes && ...)->void> callback)
-> void {
callback(std::forward<ResourceTypes>(resources)...);
};
}
try {
with(Resource())([](Resource const && resource) -> void {
spdlog::info("after init of {}", static_cast<void const *>(&resource));
});
[](auto const &&...) { spdlog::info("after init"); });
}catch(...){}
Through perfect forwarding an arbitrary amount of resources can be initialized in the resource block head and passed down into the inner body lambda, where the main code is to be executed. The resources can be taken and used; or ignored. After the lambda is finished, the resources go out of scope and RAII kicks in and cleans up.
According to compiler outputs (on compiler explorer), the indirections are not visible with a little bit of optimization turned on.
This little piece clearly helps visualizing the intend and puts a nice scope around it's usage. I like it ☺
Keine Kommentare:
Kommentar veröffentlichen