Closed rafjmac closed 6 months ago
We don't have first class support for non single polymorphic service, but you can definitely roll up your own service kind that does just that.
You're not the first one to ask for such feature, but I haven't find a way to implement a generic solution for this just yet.
kgr::service
will always return by value, and a polymorphic override requires the service to be single. The library detects such conflict and refuse your service definition, hence your error of a deleted function.
To fix this you can create a custom service definition that contains a factory method that calls the container for a new instance, and return by std::unique_ptr
. The interface is a bit hard to understand in kangaru 4, but not impossible to do. We have a documentation page for custom service definition and an example.
Let me know if you need additional support.
Hi,
Thanks for the explanation.
Also, I have one additional question - does the autowire
feature work with interfaces? I read issue https://github.com/gracicot/kangaru/issues/111, tried to compile and it worked correctly. However, I tried to add another class that uses AbstractCamera&
but it was not compiling.
I investigated the issue I had and the problem was that I added a virtual destructor - so apparently no problem with inheritance, etc. but the virtual destructor made my code to not compile. Here is the example if you want to try yourself:
#include <iostream>
#include <kangaru/kangaru.hpp>
struct autowire_abstract
{
template <typename T> struct Service : kgr::abstract_service<T>
{
};
template <typename T> using mapped_service = Service<std::decay_t<T>>;
};
template <typename... Overrides> struct autowire_override
{
template <typename T>
struct Service : kgr::single_service<T, kgr::autowire>, kgr::overrides<kgr::mapped_service_t<Overrides>...>
{
};
template <typename T> using mapped_service = Service<std::decay_t<T>>;
};
struct autowire_polymorphic
{
template <typename T> struct Service : kgr::single_service<T, kgr::autowire>, kgr::polymorphic
{
};
template <typename T> using mapped_service = Service<std::decay_t<T>>;
};
struct AbstractCamera
{
virtual ~AbstractCamera() = default;
virtual void projection() = 0;
friend auto service_map(AbstractCamera const&) -> autowire_abstract;
};
struct Camera : AbstractCamera
{
~Camera() = default;
void projection() override
{
std::cout << "default projection" << std::endl;
}
friend auto service_map(Camera const&) -> autowire_override<AbstractCamera>;
};
int main()
{
auto c = kgr::container{};
c.emplace<kgr::mapped_service_t<Camera>>();
c.invoke([](AbstractCamera& c) { c.projection(); });
}
What compiler do you use? With GCC 13 this code compiles correctly and runs. I got the output default projection
Ah okay, I haven't checked any other one. I use Visual Studio 17 2022. Then it seems like a bug in MSVC.
Checked with Clang 17.0.6 on windows and it works.
Let me see what I can do to help MSVC with this one
There's a simple workaround for this problem. Simply probe the service map using const ref types:
template <typename... Overrides> struct autowire_override
{
template <typename T>
struct Service : kgr::single_service<T, kgr::autowire>, kgr::overrides<kgr::mapped_service_t<Overrides const&>...>
{
};
template <typename T> using mapped_service = Service<std::decay_t<T>>;
};
The root cause seems similar to issue #113 which means little can be done on my side to fix this issue without major refactoring of how the service map works, and modern technique that would make it possible are simply not available in the compilers kangaru 4 is set to support.
Since there is an easy workaround I will close this issue. Let me know if despite the workaround you still experience difficulties with autowire on msvc.
Hi,
I am currently investigating possibilities of the kangaru and I have a problem defining a polymorphic service which shall not be a single one:
Error that pops up is about deleted function
emplace<PerspectiveCameraService>()
. What I am trying to get is that there is some interface class but in case anyone wants to use it, it must get a unique instance. I haven't gone through details of the library, but I hope you can answer whether it is possible but I am doing something wrong or support for such case was not planned.