|
Boost : |
From: Vladimir Prus (ghost_at_[hidden])
Date: 2004-07-23 04:49:22
Hi Sven,
> > Probably, you could start by explaining your vision of the library first.
> > Of three points you've given:
>
> The problems I would like to solve for myself are:
>
> 1) Often you need to write progams that need to work on different versions
> of a particular OS, with later versions having additional API calls that
> you could use.
> void MyAPIStub()
> {
> static imported_function<void()> apiFunc( "ApiFunc", "OSLib" );
>
> if ( !apiFunc )
> {
> // do something here
> }
>
> apiFunc();
I think this is reasonable use case. I wanted something similiar recently. I
have a library which calls user-provided 'userinit' function. To allow the
user to not provide the function, the library has its own definition. So,
when the library's version is called, it call 'dlsym' to find the 'next'
definition of 'userinit' and if it exists, calls it.
But I'm afraid this semantic (find the next definition of symbol) is
Unix-specific. I'm not even sure if two symbols with the same names in
different DLLs are allowed on Windows.
> Altough I acknowlege that the locking required in multi-threaded progams
> would clutter the syntax (more than) a little.
I'm not sure it's necessary, unless the called function is not thread-safe.
> 2) When creating plugin interfaces, having to go through extern "C" is a
> bit ugly to me. At the same time it ditches the C++ type safety. Being able
> to export a C++ plugin function and have the import library figure out the
> name mangling for me would improve the both the readability and the
> correctness of the program
I don't care that much about type safety of a single function, given that
implementing that type-safety can be hard. But, of course, this would be a
nice addition if you want to code it ;-)
I'm more interested in nice interface to declare plugins. For example, on Unix
static initialisers in a library are run when it's opened, so you can do
something like this:
extern std::map<std::string, Codegen*> codegens;
// defined somewhere in application
class Codegen1 {};
class Codegen2 {};
RegisterHelper<Codegen1> X(codegens, "1");
RegisterHelper<Codegen1> X(codegens, "2");
But will this work for Windows? Can DLL have unresolved external references?
Are static initializers run when DLL is opened?
If not, we'd have to do much less nice:
void init_codegens(std::map<....>& m)
{
m["1"] = new Codegen1;
m["2"] = new Codegen2;
}
It's less nice, because the first approach allows to register different
codegens in different translation units.
BTW, I think if you want typesafety, not don't need overloading, you can do
this:
// caller
typedef void (right_type)(int, foo, bar);
void* fp = ... get raw pointer to function ...;
((right_type*)fp)(....., typeid(right_type).name());
// callee
typedef void (right_type)(int, foo, bar);
void func(int, foo, bar, char* sig)
{
assert(strcmp(sig, typeid(right_type).name()) == 0);
.....
}
> > boost::function<void (void)> f
> > = static_cast<void (*void)>dlsym(h, "whatever")
> >
> > - Volodya
>
> Yeah, yesterday morning I was already thinking more of something like this
>
> boost::function<void()> f1 = import<void()>( "lib", "whatever" );
> boost::function<void()> f2 = import<void()>( lib, "whatever" );
> boost::function<void()> f3 = import<void()>( lib, "whatever",
> some_decorator () );
Yes, I think that's just as fine. I'm a bit suspicious about passing library
name as string -- you'd need to keep a list of all opened dll handles
somewhere. Maybe just class 'dll' with method 'import'?
> As far as the cdecl decorator and the tool is concerned. I have always
> considered it very likely that I would fail and not achieve what I want,
> but that won't stop me from trying.
;-) Just keep us informed somehow... I'd be interested in working on this too,
though won't have any time till September.
- Volodya
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk