[Utility] intuitive scoping with BOOST_WITH

Hi Everyone, What if you could do std::mutex the_mutex; using Lock = std::unique_lock<std::mutex>; void f() { with(Lock{the_mutex}) { do_something(); do_other_thing(); } } *...or...* struct Pushed_matrix { Pushed_matrix() { glPushMatrix(); } ~Pushed_matrix() { glPopMatrix(); } }; void f() { with(Pushed_matrix{}) draw_something(); } At C++Now (2015), I presented this idea of mine and a macro implementation (BOOST_WITH) in a lightning talk. Since reception was good and more serious than the talk itself, I continued to work on it. I would appreciate informal review and opinions: https://github.com/maysl/BOOST_WITH Marcel

On 07.08.2015 03:09, Marcel Ebmer wrote:
I don't think this utility gives much compared to the naive macro-less solution: f() { { Lock lock{the_mutex}); do_something(); do_other_thing(); } do_something_without_a_lock(); } Also, your macro requires the type to be movable. This seems like a rather strong requirement. For instance, it won't work with lock_guard. If you really want to improve it you might want to use 'for' statement instead of 'if', something along these lines: template< typename T > struct with_value { T value; bool guard; }; #define BOOST_WITH(x)\ for (with_value<decltype(x)> w{x, true}; w.guard; w.guard=false) There is another limitation that is not so easy to lift - you cannot access the guard value from within the scope. For instance, you cannot use the lock to block on a condition variable.

Andrey Semashev <andrey.semashev <at> gmail.com> writes:
Hi Andrey, Sorry, didn't get the idea. How does for loop solve the problem with non-movable types? I'd also note that it's possible to do that as follows #define WITH_IMP(code) code } #define WITH(x) {const decltype(x)& _unique = x; (void)_unique; WITH_IMP std::mutex m; WITH(std::lock_guard<std::mutex>{}) ( do_something(); ) But in this case habitual brace syntax is lost. So after all I would rather stick to usual C++ scoped style.

Thank you Andrey, On 08/07/2015 11:07 AM, Andrey Semashev wrote: > On 07.08.2015 03:09, Marcel Ebmer wrote: >> ... >> https://github.com/maysl/BOOST_WITH > > I don't think this utility gives much compared to the naive macro-less > solution: > > f() { > { > Lock lock{the_mutex}); > do_something(); > do_other_thing(); > } > do_something_without_a_lock(); > } Your example nicely shows two things I want to overcome with 'with' 1) You define a variable that you never use 2) The solution, using an explicit scope, is not very expressive > > Also, your macro requires the type to be movable. This seems like a > rather strong requirement. For instance, it won't work with > lock_guard. If you really want to improve it you might want to use > 'for' statement instead of 'if', something along these lines: > I simply did not find a way to implement this for non-movable types (like lock_guard). Naturally, if there is one, I would be delighted! > template< typename T > > struct with_value > { > T value; > bool guard; > }; > > #define BOOST_WITH(x)\ > for (with_value<decltype(x)> w{x, true}; w.guard; w.guard=false) > The 'for' loop solution has a serious flaw in that you change the meaning of 'break' and 'continue': while (true) BOOST_WITH(whatever) // for(...) if (something) break; // breaks the single-pass for loop > There is another limitation that is not so easy to lift - you cannot > access the guard value from within the scope. For instance, you cannot > use the lock to block on a condition variable. > This limitation is 100% intentional. When I need access to the scoped variable, BOOST_WITH is not the way to go. The macro (or the hypothetical with-statement) is meant for the not so uncommon case where you do not care about the variable name. In fact, I originally had the idea because I had discovered this bug: void f() { std::lock_guard<std::mutex>{the_mutex}; // name missing, only a temporary do_something(); // the_mutex not locked } Marcel
participants (3)
-
Andrey Semashev
-
Anton Bikineev
-
Marcel Ebmer