Closed timofurrer closed 5 years ago
Yes. In fact, as for now all single services are allocated on the heap so their address stay stable.
The confusion might come from the fact that service are injected and returned by reference.
So for a single service you can use it like that:
struct Foo {};
struct FooService : kgr::single_service<Foo> {};
Foo* foo_ptr = &container.service<FooService>();
Foo& foo_ref = container.service<FooService>();
assert(foo_ptr == &foo_ref); // passes
If on the contrary your service is not a single, they are by default injected and returned by value:
struct Foo {};
struct FooService : kgr::service<Foo> {};
Foo foo_value = container.service<FooService>();
From what I understand you desire to have raw (non owning) pointer by default for single and std::unique_ptr
for non-single?
To enable std::unique_ptr
on a non-single, simply use kgr::unique_service
:
struct Foo {};
struct FooService : kgr::unique_service<Foo> {};
std::unique_ptr foo_ptr = container.service<FooService>();
For raw pointer on single services, it takes an extra step. You'll have to extend the library to add support for raw pointer injection:
template<typename T, typename Dependencies>
struct raw_single_service : kgr::single_service<T, Dependencies> {
auto forward() const -> T* {
return &this->instance();
}
};
Then use your new service type:
struct Foo {};
struct FooService : raw_single_service<Foo> {};
// Yay! Pointer by default
Foo* foo_ptr = container.service<FooService>();
That should be it! Thanks for reporting an issue. Please tell me if this solves your problem.
The part with the unique_service<>
was exactly what I was looking for.
Thanks for the quick help!
Is it also possible to emplace
a unique_ptr
as an external service? Is there something like an extern_unique_service
?
Or a way to transfer ownership of a raw pointer?
No that won't work with the current model. You see, kgr::unique_service
is not a single service. Everytime you ask the container for an instance of it, it will construct a new one. So I don't see a way it could contain one and also construct a new one each time. container.emplace<...>(...)
only work for single service, because it's the only kind the container need to contain.
For a unique service it cannot a single service since it would require to copy the unique pointer (or worse, return a unique pointer by reference). How would the container return the same std::unique_ptr
(the one you emplaced) each time you call container.service<...>()
?
Maybe you want a factory function from your code to be called by the container each time you ask for a std::unique_ptr<Foo>
?
If you have an already constructed std::unique_ptr<Foo>
that the container need to inject into other services as reference then you need kgr::extern_service<Foo>
and set the instance with container.emplace<FooService>(foo_uptr.get())
. Your current system stay the owner of the unique pointer, and the container simply use a raw pointer to it.
If you need the same thing but with services injected as a raw pointer that comes from that unique_ptr, then you will need a similar adaptation as my other comment:
template<typename T>
struct extern_rawptr_service : kgr::extern_service<T> {
auto forward() const -> T* {
return &this->instance();
}
};
Thanks!
I've now used the extern_rawptr_service
you've provided above and declared a service like this:
struct FooService : extern_rawptr_service<IBarTpl<Bar>> {};
Now I struggle to supply the instance. What I've tried:
IBarTpl<Bar> *b = ...;
container.emplace<FooService>(b);
The error seem to be somewhere at:
/usr/include/kangaru/container.hpp:521:3: error: no matching function for call to ‘kgr::container::make_contained_service(IBarTpl<Bar> *)’
Any ideas what I'm doing wrong here? Do I need to provide another helper in my extern_rawptr_service
definition?
I could solve it by emplacing with a reference instead of the pointer: container.emplace<FooService>(*b)
.
Ah yes true, it will need a reference. I forgot that detail. This is because we defined extern_rawptr_service
as extending kgr::extern_service
which contains a reference.
This could technically be solved by using that instead:
template<typename Type>
struct extern_rawptr_service : kgr::single_service<Type*>, kgr::supplied {};
And that is better since it's simpler.
Here's a live example.
Anyways, I'm glad my help has been useful to you. If you need anything else, please open a new issue!
Is it possible to receive a
unique_ptr
or raw pointer from aservice()
call?Something like this:
Or is there any other way to let kangaru create the requested service on the heap?