Boost logo

Boost :

From: Douglas Gregor (gregod_at_[hidden])
Date: 2002-07-29 13:09:41


On Saturday 27 July 2002 05:33 pm, Thomas Wenisch wrote:
[snip requirements]
> My current thought is that the glue should work like this:
>
> struct c_style_object_GlueClass {
> struct POD_glue {
> c_style_object_t c_style_iface;
> CppStyleImplementation *cpp_implementation;
> };
>
> static POD_glue * construct() {
> cpp_implementation = new CppStyleImplementation();
> c_style_iface.callback = & Trampoline<c_style_object_t,
> & CppStyleImplementation::callback>::trampoline;
> }
> };
>
> The glue class provides a POD struct so that when the C code calls the
> trampoline with a c_style_object_t *, the trampoline can safely upcast to
> POD_glue * and then access the cpp_implementation. Trampoline<> is a
> magic template that somehow takes apart the C style typedef and the
> provided member function pointer to the C++ function, and creates the
> correct trampoline with a signature matching the typedef, or generates a
> compile error if the supplied typedef and function cannot possible by
> connected to each other (ie completely different arities, incovertible
> paramter types, etc).
>
> The GlueClass itself would ideally be a template that takes on as much of
> the work of glueing the C and C++ together, for example, defining the
> struct type.
>
> The sytax above is all hypothetical, and I'm not married to any of it (ie
> the templates may need more/different parameters or invocation syntax).

It seems like you could create a reasonably good generic trampoline like this:

// The trampoline itself
template<typename Functor, typename DecodePolicy,
               typename R, typename T1, typename T2, ..., typename TN>
R invokerN(T1 a1, T2 a2, ..., TN aN)
{
  DecodePolicy decode;
  Functor* f = decode(a1, a2, ..., aN);
  return (*f)(a1, a2, ..., aN);
}

// A type that is convertible to a trampoline of any type that calls a
// function object 'Functor'.
// DecodePolicy helps get the function object out of the parameters
// given to the trampoline
template<typename Functor, typename DecodePolicy>
class trampoline_t
{
public:
  trampoline_t(Functor f) : functor(f) {}

  template<typename R, typename T1, typename T2, ..., typename TN>
  operator R (*())(T1, T2, ..., TN) const
  {
    return &invokerN<Functor, DecodePolicy, R, T1, T2, ..., TN>;
  }
};

Unfortunately, I can't seem to construct the appropriate conversion operator
to a function pointer R (*)(T1, T2, ..., TN). <stomps off muttering about C
declarator syntax>

> Here are my questions for the Boost community:
>
> 1) Can some combination of Boost.Function, Boost.Bind, etc already
> accomplish what I need?

Not that I can see.

> 2) Is this kind of template possible, or am I hopelessly doomed by
> calling convention problems. In otherwords, can a C++ template generate a
> function whose address I can pass to C code and expect it to work?

I believe the answer is 'yes'. Otherwise, there would be no C/C++
compatibility.

> 3) If the answer to 1 is no, and the answer to 2 is yes, would anyone
> else out there benefit from a facility like this?
>
> If the answer is yes, I will try to come up with a generic solution that
> may be appropriate for Boost (ie follow style guidelines, etc). If no one
> else needs it, I will save myself the trouble and just solve my immediate
> problem.

I've had to solve a similar problem before, except that it wasn't an OO-style
C framework (with a c_style_object_t* parameter) but instead had a void*
parameter for user data. There's a writeup of my approach here:
  
http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?Generalizing_C-Style_Callbacks

My major concern with creating a generic solution is the storage management.
The trampoline requires state, which generally must be allocated on the heap,
but if the trampoline allocates the state how is it deallocated? There are
also many different ways to store the state, depending on how the user data
is returned via the callback (e.g., in a void pointer, in a structure, in the
POD_glue that's been cast to c_style_object_t, etc.)

> 4) Is there any chance the typedef "parsing" templates that are now in
> Boost.Function could be extracted and moved into the Type Traits
> library?

Yes, it's possible. The main sticking point for me is how to encode the
argument list. If MPL is accepted, that might be the answer.

> Also, it would be nice if there was one template that could figure out
> arity, argument, and return types whether the construct passed to it is a
> pointer-to-fn, reference-to-fn, fn-type, or the corresponding mem-fn
> types. From my reading of it, the code in Boost.Function only works for
> function types, and not pointers, references, or member functions.

Yes, that's correct. The new Boost.Function syntax uses function types
directly.

        Doug


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk