Click here to Skip to main content
15,886,110 members
Articles / Programming Languages / C++

Fast C++ Delegate

Rate me:
Please Sign up or sign in to vote.
4.80/5 (52 votes)
27 Mar 2006CPOL19 min read 211.8K   3.6K   110  
An implementation of a fast C++ delegate which is portable and C++ Standard-compliant.
/** @file bindtmpl.h
 *
 *  @brief  helper functions (fd::make_delegate)
 *
 *
 *  @author JaeWook Choi
 *  @version 1.10
 *
 *  @history
 *    1.10 (03.12.2006) - see history of "delegateimpl.h"
 *    1.01 (03.10.2006) - make_delegate implementation is separated from delegatetmpl.h
 *                        removed type-check relaxation version of make_delegate
 *                        (make_delegate is automatic type deduction function and it is not
 *                         useful at all in type-check relaxation mode)
 *
 *
 * This software is provided "as is" without express or implied warranty, and with
 * no claim as to its suitability for any purpose.
 *
 */

// Note: this header is a header template and must NOT have multiple-inclusion
// protection.

namespace fd
{

template<typename R FD_COMMA FD_TPARMS(N)> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (*fn)(FD_TARGS(N)))
{
  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(fn);
}

#if defined(FD_FN_ENABLE_STDCALL)

template<typename R FD_COMMA FD_TPARMS(N)> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_STDCALL_ *fn)(FD_TARGS(N)))
{
  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(fn);
}

#endif  // #if defined(FD_FN_ENABLE_STDCALL)

#if defined(FD_FN_ENABLE_FASTCALL)

template<typename R FD_COMMA FD_TPARMS(N)> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_FASTCALL_ *fn)(FD_TARGS(N)))
{
  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(fn);
}

#endif  // #if defined(FD_FN_ENABLE_FASTCALL)

#if defined(FD_FN_ENABLE_PASCAL)

template<typename R FD_COMMA FD_TPARMS(N)> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_PASCAL_ *fn)(FD_TARGS(N)))
{
  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(fn);
}

#endif  // #if defined(FD_FN_ENABLE_PASCAL)

// ====================================================================================================
// member function argument binding
// ====================================================================================================

#if !defined(FD_DISABLE_CLONE_BOUND_OBJECT)
template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (U::*mfn)(FD_FPARMS(N)), T & obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_REF(U *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, obj);
}

template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (U::*mfn)(FD_FPARMS(N)) const, T & obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_REF(U const *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, obj);
}
#endif  // #if !defined(FD_DISABLE_CLONE_BOUND_OBJECT)

template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (U::*mfn)(FD_FPARMS(N)), T * obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_PTR(U *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, get_pointer(obj));
}

template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (U::*mfn)(FD_FPARMS(N)) const, T * obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_PTR(U const *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, get_pointer(obj));
}

#if defined(FD_MEM_FN_ENABLE_STDCALL)

#if !defined(FD_DISABLE_CLONE_BOUND_OBJECT)
template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_STDCALL_ U::*mfn)(FD_FPARMS(N)), T & obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_REF(U *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, obj);
}

template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_STDCALL_ U::*mfn)(FD_FPARMS(N)) const, T & obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_REF(U const *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, obj);
}
#endif  // #if !defined(FD_DISABLE_CLONE_BOUND_OBJECT)

template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_STDCALL_ U::*mfn)(FD_FPARMS(N)), T * obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_PTR(U *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, get_pointer(obj));
}

template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_STDCALL_ U::*mfn)(FD_FPARMS(N)) const, T * obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_PTR(U const *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, get_pointer(obj));
}

#endif  // #if defined(FD_MEM_FN_ENABLE_STDCALL)

#if defined(FD_MEM_FN_ENABLE_FASTCALL)

#if !defined(FD_DISABLE_CLONE_BOUND_OBJECT)
template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_FASTCALL_ U::*mfn)(FD_FPARMS(N)), T & obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_REF(U *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, obj);
}

template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_FASTCALL_ U::*mfn)(FD_FPARMS(N)) const, T & obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_REF(U const *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, obj);
}
#endif  // #if !defined(FD_DISABLE_CLONE_BOUND_OBJECT)

template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_FASTCALL_ U::*mfn)(FD_FPARMS(N)), T * obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_PTR(U *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, get_pointer(obj));
}

template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_FASTCALL_ U::*mfn)(FD_FPARMS(N)) const, T * obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_PTR(U const *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, get_pointer(obj));
}

#endif  // #if defined(FD_MEM_FN_ENABLE_FASTCALL)

#if defined(FD_MEM_FN_ENABLE_CDECL)

#if !defined(FD_DISABLE_CLONE_BOUND_OBJECT)
template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_CDECL_ U::*mfn)(FD_FPARMS(N)), T & obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_REF(U *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, obj);
}

template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_CDECL_ U::*mfn)(FD_FPARMS(N)) const, T & obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_REF(U const *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, obj);
}
#endif  // #if !defined(FD_DISABLE_CLONE_BOUND_OBJECT)

template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_CDECL_ U::*mfn)(FD_FPARMS(N)), T * obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_PTR(U *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, get_pointer(obj));
}

template<typename R FD_COMMA FD_TPARMS(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>
make_delegate(R (FD_CDECL_ U::*mfn)(FD_FPARMS(N)) const, T * obj)
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK_OBJ_PTR(U const *, obj);

  return FD_JOIN(delegate,N)<R FD_COMMA FD_TARGS(N)>(mfn, get_pointer(obj));
}

#endif  // #if defined(FD_MEM_FN_ENABLE_CDECL)

// ====================================================================================================

#if N > 0

//
// make_delegate_adpater() for member function adapter
//
// When using make_delegate() helper function for member function adapter,
// it is impossible to tell whether member function adapter is used in the
// pointer form (1) or in the reference form (2), therefore only pointer form (1)
// of make_delegate() for member function adapter will be enabled
//

// ----------------------------------------------------------------------
//
// 1)
// template<typename T>
// R operator()(cv-quals T * px, T1 p1, T2 p2, ..., Tn pn) cv-quals
// {
//   return px->.*mf(p1, p2, ..., pn);
// }
//
// (NOTE)
//
// the first argument of the pointer to object is only used for providing explicit type
// information about the member function which is being stored
//
// (why?)
//
// class Base
// {
// public:
//   virtual int foo(int);
// };
// class Derived : public Base
// {
// };
// template<typename T>
// void bar(int (T::*mfn)(int))
// {
//   enum { assertion = fd::util::Is_same<T, Derived>::value };
//   FD_STATIC_ASSERT(assertion);
// }
// int main()
// {
//   bar(&Derived::foo);  // cause FD_STATIC_ASSERT() in bar() at compile time !!!
// }
//
// In the code snippet shown above, typename 'T' is found to be 'Base' not 'Derived'
// even though member function pointer was specified as &Derived::foo when calling bar().
// therefore, to make make_delegate() to work as the user intended, explicit type info.
// should be passed over into make_delegate() call, something like,
//
// fd::delegate2<int, Derived *, int> dg = make_delegate((Derived *)0, &Derived::foo);
//
// If explicit type info. is passed over into make_delegate() as the second argument instead,
// it will confuse the compiler as its signature become exactly same as
// the member function with binging object version of make_delegate(), So type info.
// passed over into make_delegate() as the first argument to distinguish b/w them.
//
// It isn't really nice, but I don't see any better solution for this
//

template<typename R FD_COMMA_SP FD_TPARMS_SP(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>
make_delegate(T *, R (U::*mfn)(FD_FPARMS_SP(N)))
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK(U *, T *);

  return FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>(mfn);
}

template<typename R FD_COMMA_SP FD_TPARMS_SP(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>
make_delegate(T *, R (U::*mfn)(FD_FPARMS_SP(N)) const)
{
  FD_PARAM_TYPE_CHK(U const *, T *);

  return FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>(mfn);
}

#if defined(FD_MEM_FN_ENABLE_STDCALL)

template<typename R FD_COMMA_SP FD_TPARMS_SP(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>
make_delegate(T *, R (FD_STDCALL_ U::*mfn)(FD_FPARMS_SP(N)))
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK(U *, T *);

  return FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>(mfn);
}

template<typename R FD_COMMA_SP FD_TPARMS_SP(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>
make_delegate(T *, R (FD_STDCALL_ U::*mfn)(FD_FPARMS_SP(N)) const)
{
  FD_PARAM_TYPE_CHK(U const *, T *);

  return FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>(mfn);
}

#endif  // #if defined(FD_MEM_FN_ENABLE_STDCALL)

#if defined(FD_MEM_FN_ENABLE_FASTCALL)

template<typename R FD_COMMA_SP FD_TPARMS_SP(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>
make_delegate(T *, R (FD_FASTCALL_ U::*mfn)(FD_FPARMS_SP(N)))
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK(U *, T *);

  return FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>(mfn);
}

template<typename R FD_COMMA_SP FD_TPARMS_SP(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>
make_delegate(T *, R (FD_FASTCALL_ U::*mfn)(FD_FPARMS_SP(N)) const)
{
  FD_PARAM_TYPE_CHK(U const *, T *);

  return FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>(mfn);
}

#endif  // #if defined(FD_MEM_FN_ENABLE_FASTCALL)

#if defined(FD_MEM_FN_ENABLE_CDECL)

template<typename R FD_COMMA_SP FD_TPARMS_SP(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>
make_delegate(T *, R (FD_CDECL_ U::*mfn)(FD_FPARMS_SP(N)))
{
  // to prevent non-const member function call on const object
  FD_PARAM_TYPE_CHK(U *, T *);

  return FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>(mfn);
}

template<typename R FD_COMMA_SP FD_TPARMS_SP(N), typename U, typename T> inline
FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>
make_delegate(T *, R (FD_CDECL_ U::*mfn)(FD_FPARMS_SP(N)) const)
{
  FD_PARAM_TYPE_CHK(U const *, T *);

  return FD_JOIN(delegate,N)<R, T * FD_COMMA_SP FD_TARGS_SP(N)>(mfn);
}

#endif  // #if defined(FD_MEM_FN_ENABLE_CDECL)

#endif  // #if N > 0

}  // namespace fd

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Other
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions