|
Boost : |
From: sanichin_at_[hidden]
Date: 2001-11-05 01:46:41
First, Peter thanks for a wonderful set of templates. I've wanted
something like this for a while, but haven't ever taken the
considerable amount of time and effort to implement it. Now I don't
have to.
You know someone is using your stuff when they request features...
My problem concerns calling conventions. Yes, I know these use
compiler-specific keywords. I'm asking for a general-case, compiler-
independent change to boost:mem_fn that will make dealing with this
compiler specific stuff easier.
For example, at least a couple Windows compilers support the
__stdcall calling convention, where the callee removes parameters
from the stack. The Win32 API and COM objects use this calling
convention.
A __stdcall member function pointer looks like this:
typedef void (__stdcall T::*SomeMemberFunctionPtr)();
I have a bunch of COM objects in a STL container. I want to use
std::for_each and boost::bind to call a method on all the objects in
the container. The method I want to call uses the __stdcall calling
convention. Thus it doesn't compile, because boost::bind expects
void (T::*)();
Which is how it should be.
But what I've had to do to solve the problem is basically re-
implement ALL of mem_fn.hpp, and implement my own bind function
templates. A simple generic, compiler-independent change to
boost::mem_fn could at least simplify the work of supporting compiler-
specific calling conventions.
The idea I used was to use a traits struct to specify the type of the
function pointer. This is best illustrated through code:
// ********* BEGIN CODE *********
namespace boost
{
// calling convention traits
template <class R, class T> struct mem_fun_traits_0
{
typedef R (T::*mem_func_type)();
typedef R (T::*const_mem_func_type)() const;
};
#if defined(_MSC_VER)
template <class R, class T> struct mem_fun_stdcall_traits_0
{
typedef R (__stdcall T::*mem_func_type)();
typedef R (__stdcall T::*const_mem_func_type)() const;
};
#endif
namespace _mfexi // mem_fun_ex_impl
{
// mf0
template<class R, class T, class F=typename mem_fun_traits_0<R,
T>::mem_func_type >
class mf0
{
public:
typedef R result_type;
typedef T * first_argument_type;
private:
F f_;
public:
// UNCHANGED STUFF REMOVED
};
} // namespace _mfexi
#if defined(_MSC_VER)
template<class R, class T> _mfexi::mf0<R, T, typename
mem_fun_stdcall_traits_0<R, T>::mem_func_type>
mem_fn_ex(R (__stdcall T::*f)())
{
return _mfexi::mf0<R, T,mem_fun_stdcall_traits_0<R,
T>::mem_func_type>(f);
}
// define new bind templates
// 0
template<class R, class T,
class A1>
_bi::bind_t<R, _mfexi::mf0<R, T, typename
mem_fun_stdcall_traits_0<R, T>::mem_func_type>, typename
_bi::list_av_1<A1>::type>
BOOST_BIND(R (__stdcall T::*f) (), A1 a1)
{
typedef _mfexi::mf0<R, T, mem_fun_stdcall_traits_0<R,
T>::mem_func_type> F;
typedef typename _bi::list_av_1<A1>::type list_type;
return _bi::bind_t<R, F, list_type>(F(f), list_type(a1));
}
#endif // _MSC_VER
} // namespace boost
// ******** END CODE ************
By using the traits class, I can easily reuse the same member
function class implementation for a varied number of calling
conventions. The original mem_fn function templates and bind
templates remain unmodified for the default calling convention case.
It's not necessary to add the stuff wrapped in #if defined(_MSC_VER)
to boost itself. While it'd be a convenient implementation detail for
folks like me, just having mem_fn accept a traits class for member
function pointer types would simplify my life.
As an aside, #if defined(_MSC_VER) is probably not the way to check
for __stdcall anyway. Really, I should probably check to see if I'm
on the Windows platform, as I can't see how a compiler could work on
Windows without supporting those calling conventions and keywords,
since __stdcall is used throughout the Windows headers.
-steve anichini
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk