[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:
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:
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:
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)
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 Andrey Semashev
- 
                 Anton Bikineev Anton Bikineev
- 
                 Marcel Ebmer Marcel Ebmer