The Auto
macro
Auto
macroI’ve been talking about this one since 2014. The contents of “Auto.h” fit comfortably on a single slide:
#pragma once
template<class L>
class AtScopeExit {
L& m_lambda;
public:
AtScopeExit(L& action) : m_lambda(action) {}
~AtScopeExit() noexcept(false) { m_lambda(); }
};
#define TOKEN_PASTEx(x, y) x ## y
#define TOKEN_PASTE(x, y) TOKEN_PASTEx(x, y)
#define Auto_INTERNAL1(lname, aname, ...) \
auto lname = [&]() { __VA_ARGS__; }; \
AtScopeExit<decltype(lname)> aname(lname);
#define Auto_INTERNAL2(ctr, ...) \
Auto_INTERNAL1(TOKEN_PASTE(Auto_func_, ctr), \
TOKEN_PASTE(Auto_instance_, ctr), __VA_ARGS__)
#define Auto(...) \
Auto_INTERNAL2(__COUNTER__, __VA_ARGS__)
Wrap any arbitrary amount of code in Auto(...)
to generate a hygienic “scope guard.”
bool Mutate(State *state)
{
state->DisableLogging();
Auto(state->EnableLogging());
if (!state->AttemptOperation1()) return false;
if (!state->AttemptOperation2()) return false;
return true;
}
This scope guard has perfect codegen with zero overhead
(at -O2
) on all major compilers. Because it requires no explicit captures, no novel
variable name, and no special treatment for this
, it is highly suited for
mechanically generated code. It is portable all the way back to C++11.
void Example()
{
Auto(
puts("starting the first Auto");
Auto(puts("cleaning up in the second Auto"));
puts("getting ready to clean up in the first Auto");
);
puts("doing the main operation");
}
See also:
- “Feature requests for the
Auto
macro” (2024-02-14)
Posted 2018-08-11