Boost logo

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