Boost logo

Boost :

From: Richard Hodges (hodges.r_at_[hidden])
Date: 2021-02-23 14:48:45


On Tue, 23 Feb 2021 at 14:59, Krzysztof Jusiak via Boost <
boost_at_[hidden]> wrote:

> >
> > That's not exactly what I meant.
> >
> > What I meant is that if library A uses DI mechanism A, can I describe to
> > a Boost.DependencyInjection that mechanism A, such that mechanism A maps
> > 100% into Boost.DependencyInjection.
> >
> > To put it back into terms of Allocators, how do I tell a
> > Boost.DependencyInjection that for all std::vector<T, X> where X meets
> > the Allocator Concept, std::vector<T, X> can have an instance X injected
> > into its construction such that one can now write:
> >
> > const auto injector = di::make_injector(
> > di::bind<std::vector>.to<MyAllocator>()
> > );
> > injector.create<std::vector<int>>()
> >
> > ... and that makes me a std::vector<int, MyAllocator<int>>.
> >
> > I'm sure it's probably possible, it's just I from my best reading of the
> > docs, I think it's quite awkward to do right now. And I think it ought
> > to not be awkward in anything Boost approves.
> >
> >
> With DI that can be already achieved with constructor/named template
> deduction.
>
> Let's try it then, shall we?
>

This is clearly stupendously clever.

What I don't understand is what specific thing is linking the bound
Allocator type in the injector to the specialisation point in the app's
constructor. Is it this:
template<class TAllocator = class Allocator>
?

This is going to need to be meticulously documented and spelled out in
small words for people like me who obviously live in your intellectual
shadow.

> For example, we have a custom allocator my_allocator
>
> template<class T> struct my_allocator : std::allocator<T> {};
>
> And 2 dependencies dep1, dep2 were we want a custom allocator to be
> injected (for vector and set)
>
> template<class TAllocator = class Allocator>
> struct dep1 {
> explicit(true) dep1(std::vector<int, TAllocator>) {}
> };
>
> template<class TAllocator = class Allocator>
> struct dep2 {
> dep2(const std::set<int, std::less<int>, TAllocator>&,
> std::unique_ptr<interface> i) {
> assert(dynamic_cast<implementation*>(i.get()));
> }
> };
>
> and the application app1, app2 (notice different constructor parameters)
>
> template<class TAllocator = class Allocator>
> struct app1 {
> app1(dep1<TAllocator>, dep2<TAllocator>) {}
> };
>
> template<class TAllocator = class Allocator>
> struct app2 {
> app2(std::shared_ptr<dep2<TAllocator>>, const dep1<TAllocator>&) {}
> };
>
> Let's make the injector and override Allocator with my_allocator
>
> auto injector = di::make_injector(
> di::bind<class Allocator>.to<my_allocator<int>>() // won't compile if
> missing (that's what means compile-time DI, it won't be an exception it
> will be a compilation error
> , di::bind<interface>.to<implementation>() // won't compile
> if missing
> );
>
> int main() {
> auto app1 = injector.create<app1>(); // Okay will create app1 with
> my_allocator injected into all dependencies which are using class Allocator
> auto app2 = injector.create<app2>(); // Okay will create app2, just a
> show-case that the order and types of constructor parameters doesn't matter
> for DI
> }
>
> Full example -> https://godbolt.org/z/sPszoG
>
> Right, now for 2e2 testing we would like to change the allocator for
> test_allocator but keep all other dependencies
>
> auto test_injector = di::make_injector(
> std::move(injector), // old injector
> di::bind<class Allocator>.to<test_allocator>() [di::override]
> );
>
> int main() {
> auto app1 = test_injector.create<app1>(); // Okay will create app1 with
> test_allocator injected into all dependencies which are using class
> Allocator
> }
>
> _______________________________________________
> Unsubscribe & other changes:
> http://lists.boost.org/mailman/listinfo.cgi/boost
>

-- 
Richard Hodges
hodges.r_at_[hidden]
office: +442032898513
home: +376841522
mobile: +376380212

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk