Вы можете получить из этого шаблона класса:
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);
}
};
И используйте это так:
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!
}
Ранее у меня была версия, которая тоже вызывала функции почты. Но я бросил это. Это потребовало бы дополнительной работы. Тем не менее, я все равно не рекомендую вам сделать эту "функцию вызова автоматически". Потому что можно легко забыть использовать синтаксис оператора-> и просто использовать точку - и внезапно пре-функция не вызывается
Обновление : вышеупомянутая версия позаботится об этом, поэтому нельзя больше случайно вызывать функции с точкой.