I am working on plugin system using Boost.dll
#include <boost/config.hpp>
#include <boost/dll/alias.hpp>
#include <memory>
class base {
public:
base(){};
~base(){};
template <typename T>
static std::shared_ptr<base> create() {
return std::make_shared<T>();
}
virtual void do1() = 0;
};
class derived : public base {
public:
derived(){};
~derived(){};
virtual void do1() override {}
};
BOOST_DLL_ALIAS(base::create<derived>, // <-- this function is exported with...
create_plugin // <-- ...this alias name
)
// auto a = base::create<derived>();
When I trying use factory method inside BOOST_DLL_ALIAS macro getting error like below.
cl /c /ID:\Download\Compressed\boost_1_67_0 a.cpp Microsoft (R) C/C++ Optimizing Compiler Version 19.12.25834 for x86 Copyright (C) Microsoft Corporation. All rights reserved. a.cpp a.cpp(27): error C2440: 'reinterpret_cast': cannot convert from 'overloaded-function' to 'intptr_t' a.cpp(27): note: Context does not allow for disambiguation of overloaded function
Without BOOST_DLL_ALIAS macro when calling factory method (as shown in last commented line), it get compiled fine.
// this really does nothing:
template<class R, class...Args>
R(*to_fptr( R(*f)(Args...) ))(Args...) {
return f;
}
// except avoid the bug in MSVC:
BOOST_DLL_ALIAS(to_fptr(base::create<derived>),
create_plugin
)
that should fix it.
MSVC seems to break when you try to cast from the name of a template function to a intptr_t. This is a bug.
The above workaround changes it from directly dealing with the name of a template function to just a function pointer. By breaking the overload resolution and the cast to intptr_t apart, MSVC no longer chokes.
You could probably also do:
template<class T>
T identity( T t ) { return std::move(t); }
instead of to_fptr
.
to_fptr
is a function that takes a function pointer and returns it. The syntax to return a function pointer from a function is a bit ridiculous, which is why it is hard to read.
Inspired by this tangentially related answer, I found another solution:
const void * create_plugin =
reinterpret_cast<const void*>(
reinterpret_cast<std::intptr_t>(
reinterpret_cast<std::decay_t<decltype(&base::create<derived>)> >(
&base::create<derived>
)
)
);
https://godbolt.org/z/NVGz_0
This should do the trick:
BOOST_DLL_ALIAS(std::function<std::shared_ptr<base>(void)>(base::create<derived>), // <-- this function is exported with...
create_plugin // <-- ...this alias name
)
Indeed it seems MSVC has a bug here, as there should be no problem taking such an expression base::create<derived>
and treating it directly as a function pointer. So instead, we "feed it a function pointer" ourselves using the magic of std::function.
I've chosen to use std::function
as it involves no writing of any kind of wrapping code and relies directly on intent-delivering standard c++ code.
And of course don't forget to #include <functional>
: )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With