I came up with a bit of C++ code that I didn't really think too much about at first until I noticed that clang accepts it but gcc doesn't. And I think gcc is probably right about it the more I think about it. The problem is, I can't really think of a good, legal way to do what I want without a ton of boilerplate.
First, here is the code I wish would compile in g++:
extern "C" template <typename T>
using factory_pointer_t = T* (*)();
Since I think this might be an XY problem, a little background. I was working on a little plugin system with a fairly simple interface. Basically it only consists of a factory function that returns a pointer to an abstract base class. The abstract base class asks for methods to deal with memory management, similar to COM. Something like this:
class ITest {
public:
virtual void release() = 0;
virtual void test_method() = 0;
protected:
virtual ~ITest(){}
};
Which would be implemented in the dynamic library something like this:
class Test : public ITest {
public:
virtual void release() override {
delete this;
};
virtual void test_method() override {
std::cout << "Hello, shared World!\n";
}
};
extern "C" ITest * testFactory() {
return new Test{};
}
The research I have done on this suggest that this should work reliably across toolchains on at least windows and linux. Even if that turns out not to be the case, the system is intended for rapid prototyping on one toolchain with the opportunity to ditch the plugins and link everything statically somewhere down the line. No problems here so far.
My other research suggests that the extern "C"
linkage specifier is very important for the dynamic linkage to work properly among all tools that support the same C ABI. The problem now is this:
I wanted to write some template code to help make some of this easier.
But no combination of extern "C"
together with the template syntax seems to work. My efforts to Google help have been thwarted by articles about the deprecated extern template
. I wanted to give it the name of an abstract interface, and have it load the dll and resolve the symbol for the factory function. But as you can see, the type of the callbacks (factory_pointer_t<T>
) are parameterized by the abstract interface pointer type they are returning. So my questions:
Should this template using directive actually compile? (It does on clang but not gcc)
If I declare my function pointer type as:
extern "C" typedef void* (*factory_pointer)();
and cast the return value explicitly with areinterpret_cast<>
, will I be invoking undefined behavior? Given that in the DLL I would like to keep the function signature that I am exporting unchanged.Do I have any other options I might not have considered for accomplishing my stated goal that don't involve
void*
?Is a typedef with
extern "C"
for the function pointer strictly necessary? The standard can't seem to make up its mind. It says for example: in 7.5 of the 2014 draft standard: "Two function types with different language linkages are distinct types even if they are otherwise identical." but in 8.3.5 paragraph 8: "The return type, the parameter-type-list, the ref-qualifier, and the cv-qualifier-seq, but not the default arguments (8.3.6) or the exception specification (15.4), are part of the function type."
I would really like to keep it working automatically in other compilers (i.e. I give it a type and tell it what library to load and I am done), but I guess I am not seeing what I need to do instead. Anything that involves more than a line of boilerplate per class, I would consider bad.
Since this is my first time experimenting with dynamic linking (more than letting the build system do it for me), I am eager to get some good advice.
In summary: I have a working solution based on the first line of code that only works in one compiler. I know it is probably wrong or at least not universally supported syntax. How do I do it the right way?