Skip to content

Instantly share code, notes, and snippets.

@gintenlabo
Last active December 21, 2015 10:09
Show Gist options
  • Save gintenlabo/6289916 to your computer and use it in GitHub Desktop.
Save gintenlabo/6289916 to your computer and use it in GitHub Desktop.
bracket on C++11
#include <utility>
namespace etude {
namespace bracket_impl_ {
namespace here = bracket_impl_;
template<class T>
T& as_lvalue(T&& x) {
return x;
}
template<class F>
struct scope_guard {
explicit scope_guard(F f)
: f_(std::forward<F>(f)) {
}
~scope_guard() {
f_();
}
// noncopyable
scope_guard(scope_guard &&) = delete;
void operator=(scope_guard&&) = delete;
private:
F f_;
};
template<class Body, class Cleanup>
auto try_finally(Body&& body, Cleanup&& cleanup)
-> decltype(body()) {
scope_guard<Cleanup&> g(cleanup);
return body();
}
template<class Acquire, class Release, class Action>
auto bracket(Acquire&& acquire, Release&& release, Action&& action)
-> decltype(action(here::as_lvalue(acquire()))) {
auto && r = acquire(); // resource
return here::try_finally(
[&] () -> decltype(action(r)) {
return action(r);
},
[&] {
release(std::forward<decltype(r)>(r));
}
);
}
template<class Before, class After, class Action>
auto bracket_(Before&& before, After&& after, Action&& action)
-> decltype(action()) {
before();
return here::try_finally(action, after);
}
} // namespace bracket_impl_
namespace bracket_adl_guard_ {
using bracket_impl_::try_finally;
using bracket_impl_::bracket;
using bracket_impl_::bracket_;
}// namespace bracket_adl_guard_
using namespace bracket_adl_guard_;
} // namespace etude
#include <iostream>
#include <memory>
template<class T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
int main() {
etude::bracket_(
[] {
std::cout << "acquire some resources\n";
},
[] {
std::cout << "release resources\n";
},
[] {
std::cout << "do something with resources\n";
}
);
try {
etude::bracket(
[] {
return make_unique<int>(42);
},
[] (std::unique_ptr<int> p) { // moved
std::cout << "release\n";
p.reset();
},
[] (std::unique_ptr<int> const& p) { // not moved
std::cout << *p << std::endl;
throw *p;
std::cout << "should not reach here.\n";
}
);
} catch (int) {
// pass
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment