You can derive from this class template:
namespace detail {
struct const_tag;
struct nonconst_tag;
/* T is incomplete yet when pre_call is instantiated.
* so delay lookup of ::impl until call to operator->
* happened and this delay_lookup is instantiated */
template<typename U, typename>
struct delay_lookup;
template<typename U>
struct delay_lookup<U, nonconst_tag>
{
typedef typename U::template get_impl<
typename U::derived_type>::type impl_type;
impl_type* u;
delay_lookup(impl_type* u):u(u) { }
impl_type* operator->() { return u; }
};
template<typename U>
struct delay_lookup<U, const_tag> {
typedef typename U::template get_impl<
typename U::derived_type>::type const impl_type;
impl_type* u;
delay_lookup(impl_type* u):u(u) { }
impl_type* operator->() { return u; }
};
} // detail::
template<typename T>
struct pre_call {
private:
friend class detail::delay_lookup<pre_call, detail::const_tag>;
friend class detail::delay_lookup<pre_call, detail::nonconst_tag>;
typedef T derived_type;
/* pre_call is the friend of T, and only it
* is allowed to access T::impl */
template<typename U> struct get_impl {
typedef typename U::impl type;
};
protected:
typedef boost::function<void(T const&)> fun_type;
fun_type pre;
template<typename Fun>
pre_call(Fun pre):pre(pre) { }
public:
/* two operator->: one for const and one for nonconst objects */
detail::delay_lookup<pre_call, detail::nonconst_tag> operator->() {
pre(*get_derived());
return detail::delay_lookup<pre_call,
detail::nonconst_tag>(&get_derived()->d);
}
detail::delay_lookup<pre_call, detail::const_tag> operator->() const {
pre(*get_derived());
return detail::delay_lookup<pre_call,
detail::const_tag>(&get_derived()->d);
}
private:
T * get_derived() {
return static_cast<T *>(this);
}
T const* get_derived() const {
return static_cast<T const*>(this);
}
};
And use it like this:
struct foo : pre_call<foo> {
private:
/* stuff can be defined inline within the class */
struct impl {
void some() const {
std::cout << "some!" << std::endl;
}
void stuff() {
std::cout << "stuff!" << std::endl;
}
};
void pre() const {
std::cout << "pre!" << std::endl;
}
friend struct pre_call<foo>;
impl d;
public:
foo():pre_call<foo>(&foo::pre) { }
};
int main() {
foo f;
f->some();
f->stuff();
// f.some(); // forbidden now!
}
Previously i had a version that called post functions too. But i dropped it. It would have needed additional work. However, i would still not recommend you to do this "call function automatically" thingy. Because one can easily forget to use the operator-> syntax and just use the dot - and suddenly have the pre function not called
Update: The version above takes care of that, so one cannot accidentally call functions with the dot anymore.