Reputation: 796
I want to create a guard, which locks a function on construction and unlocks it on destruction, e.g. calling the function with false
and true
.
class A {
void enable( bool flag );
};
within another method, I want to use:
A::anotherMethod( ... ) {
block_guard(A::enable); // now A::enable(false)
// some operation
} // now A::enable(true)
my ideas:
using template
template < class T >
class block_guard {
T t_;
public:
block_guard( T& t ) : t_(t) {
t_(false);
}
~block_guard() {
t_(true);
}
};
the question is, how to instantiate the template? maybe with boost::bind
?
using boost::function
class block_guard {
typedef boost::function< void (bool) > T;
T t_;
public:
block_guard( T& t ) : t_(t) {
t_(false);
}
~block_guard() {
t_(true);
}
};
this works fine, but the call seems to be very complicated with
block_guard bg(boost::function< void (bool) >(boost::bind(&A::enable, pointer-to-A, _1));
any ideas? maybe there is another, much simpler way?
Upvotes: 1
Views: 269
Reputation: 72063
First, realize that the member function is not all you need; you also need the object to invoke it on. There is no way in C++ for an object created in a function to implicitly capture the current this
pointer.
I'm going to assume you don't have C++11 available. If you do, using your second solution with a lambda expression is easiest.
Now, if you don't care about the slight performance hit of boost::function (and you shouldn't), the second solution is good, but I would modify it slightly to make it more convenient to use by pulling the bind into the constructor.
class block_guard {
typedef boost::function< void (bool) > block_fn;
block_fn block_fn_;
public:
// For non-member functions and function objects:
template <typename Fn>
block_guard(Fn fn) : block_fn_(fn) {
block_fn_(false);
}
// For member functions:
template <typename T, typename Ret>
block_guard(T* obj, Ret (T::*fn)(bool)) : block_fn_(boost::bind(fn, obj, _1)) {
block_fn_(false);
}
~block_guard() {
block_fn_(true);
}
};
Usage:
block_guard guard(this, &A::enable);
I use a Ret parameter here because there's no reason not to allow functions that return something - the return value will simply get ignored.
If you don't want boost::function, the thing will get less easy to use, because you have to template the block guard. It becomes useful to make a block_guard specifically for member functions then. You also lose the ability to use non-void functions.
template <typename T>
class block_guard {
typedef void (T::*block_fn)(bool);
T* obj_;
block_fn block_fn_;
public:
block_guard(T* obj, block_fn fn) : obj_(obj), block_fn_(fn) {
(obj_->*block_fn_)(false);
}
~block_guard() {
(obj_->*block_fn_)(true);
}
};
Usage:
block_guard<A> guard(this, &A::enable);
Upvotes: 2
Reputation: 17193
Yes, there is a much simpler way, forget templates, generic thing and whatever not necessary and focus on the task.
All you need is a class with a ctor and a dtor. Write the dtor first, it reveals what you will need to work. Then write the ctor, taking arguments as needed. Lastly make the unwanted functions deleted (cctor, op=). Done.
Not generic, but straight to the point.
Upvotes: 0