|
Boost : |
From: Krzysztof Jusiak (krzysztof_at_[hidden])
Date: 2021-02-23 07:49:01
>
> 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?
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
}
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk