Jeff Schwab
10/27/2008 6:13:00 PM
Ole Nielsby wrote:
> Jeff Schwab <jeff@schwabcenter.com> wrote:
>
>> Ole Nielsby wrote:
>>> VC has a __cdecl specifier which allows functions and methods to
>>> be called with varying parameter count.
>>> So, is the __cdecl specifier generally available in some form
>>> (at least on GCC with different CPU types, Mac compilers)
>>> or do I need the ellipsis?
>>> I'm designing simple plugin model for using C++ plugins in
>>> an interpreted language. I need to handle method calls with
>>> generic code.
>> Rather than passing variable-length argument lists, why not just pass
>> standard collections of arguments, e.g. in std::vectors?
>
> I want to keep the C++ plugins close to normal C++ style so
> that my C++ trained colleagues can create the plugins easily.
Passing a statically typed container by reference is "normal C++ style."
Circumventing the formal type system (e.g. with ellipses) is unusual.
> Therefore, the plugin host must translate between
> as-normal-as-possible C++ style calls and interpreted calls.
Right, so far so good. Shouldn't the host know, when it is compiled,
how many arguments each plugin function will expect? Plugins typically
have to conform to a fairly stringent API so that the host will know how
to invoke them.
> The host is compiled without specific knowledge of the signatures
> of the plugins.
It doesn't need to be too specific, but the quantity of arguments
expected by each function is pretty fundamental.
How about this: If the host provides a function template (rather than a
raw function) for registering the callbacks, then the static type of
each callback will be available to the host, and the number of arguments
can be gathered implicitly as part of the registration. Rather than
just registering a function pointer, the template instantiation (which
knows from the static type system how many arguments the callback
expects) can call an underlying registration function with both the
callback function's address and the number of arguments expected.
> Frameworks like UNO, COM, Qt... do this. I know Qt uses a
> dummy-argument technique, and that's what I intend to do too.
The only one of those I've used is Qt, and I'm not aware of it using any
kind of "dummy-argument technique." Qt uses a heavyweight preprocessor
(moc) to collect information about function signature before the C++ is
even compiled. The per-signal/slot signature information has to be
maintained at run-time by member lists of the relevant QObjects; that's
why you can only use the signal/slot mechanism with QObjects. It's a
slow, memory-hungry, error-prone technique; for example, the "types" of
function parameters are represented solely by the strings in the
function declarations, without any regard for context. If different
strings are used in the signal and slot declarations (e.g. to use local
typedefs), Qt gets confused. Qt also delays the parameter matching
until the signal/slot connections are attempted, at run-time, so you get
signal/slot mismatch errors at run-time that should have been caught at
compile-time. If you really want to go that route, be very sure you've
got test coverage for every possible connection. (Of course, that would
be difficult, since you're writing a plugin architecture.)
> I just need to be sure a caller-pops calling convention is used
> for methods - preferably without using the ellipsis in the method
> parameters of the plugins.
That's an awfully low-level set of details to be worrying about for
something as high-level as a plugin architecture, which by its nature
should probably be defined as abstractly as possible (so that a wide
variety of client code will work with it).