C++17 inversion of control and dependency injection container library.
- Constant, dynamic, and automatic resolvers
- Singleton, resolution (TODO), and unique scopes
Scope manages the uniqueness of a dependency.
Singleton scopes are cached after the first resolution and will be returned on subsequent container.get...
calls.
Resolution scopes are cached throughout the duration of a single container.get...
call. A dependency tree with duplicate dependencies will resolve each to the same cached value.
By default, the unique scope is used (except for constant values). The unique scope will resolve a unique dependency for each container.get...
call.
#include <mosure/inversify.hpp>
// for convenience
namespace inversify = mosure::inversify;
struct IFizz {
virtual ~IFizz() = default;
virtual void buzz() = 0;
};
using IFizzPtr = std::unique_ptr<IFizz>;
namespace symbols {
inline const inversify::Symbol foo { "Foo" };
inline const inversify::Symbol bar { "Bar" };
inline const inversify::Symbol fizz { "Fizz" };
inline const inversify::Symbol fizzFactory { "FizzFactory" };
inline const inversify::Symbol autoFizz { "AutoFizz" };
inline const inversify::Symbol autoFizzUnique { "AutoFizzUnique" };
inline const inversify::Symbol autoFizzShared { "AutoFizzShared" };
}
struct Fizz : IFizz {
Fizz(int foo, double bar)
:
foo_(foo),
bar_(bar)
{ }
void buzz() override {
std::cout << "Fizz::buzz() - foo: " << foo_
<< " - bar: " << bar_
<< " - counter: " << ++counter_
<< std::endl;
}
int foo_;
int bar_;
int counter_ { 0 };
};
inline static auto injectFizz = inversify::Injectable<Fizz>::inject(
inversify::Inject<int>(symbols::foo),
inversify::Inject<double>(symbols::bar)
);
inversify::Container container {};
Constant bindings are always singletons.
container.bind<int>(symbols::foo).toConstantValue(10);
container.bind<double>(symbols::bar).toConstantValue(1.618);
Dynamic bindings are resolved when calling container.get...
.
By default, dynamic bindings have resolution scope (e.g. each call to container.get...
calls the factory).
Singleton scope dynamic bindings cache the first resolution of the binding.
container.bind<IFizzPtr>(symbols::fizz).toDynamicValue(
[](const inversify::Context& ctx) {
auto foo = ctx.container.get<int>(symbols::foo);
auto bar = ctx.container.get<double>(symbols::bar);
auto fizz = std::make_shared<Fizz>(foo, bar);
return fizz;
}
).inSingletonScope();
Dynamic bindings can be used to resolve factory functions.
container.bind<std::function<IFizzPtr()>>(symbols::fizzFactory).toDynamicValue(
[](const inversify::Context& ctx) {
return [&]() {
auto foo = ctx.container.get<int>(symbols::foo);
auto bar = ctx.container.get<double>(symbols::bar);
auto fizz = std::make_shared<Fizz>(foo, bar);
return fizz;
};
}
);
Dependencies can be resolved automatically using an automatic binding. Injectables are a prerequisite to the type being constructed.
Automatic bindings can generate instances, unique_ptr's, and shared_ptr's of a class. The returned type is determined by the binding interface.
container.bind<Fizz>(symbols::autoFizz).to<Fizz>();
container.bind<IFizzUniquePtr>(symbols::autoFizzUnique).to<Fizz>();
container.bind<IFizzSharedPtr>(symbols::autoFizzShared).to<Fizz>().inSingletonScope();
auto bar = container.get<double>(symbols::bar);
auto fizz = container.get<IFizzPtr>(symbols::fizz);
fizz->buzz();
auto fizzFactory = container.get<std::function<IFizzPtr()>>(symbols::fizzFactory);
auto anotherFizz = fizzFactory();
anotherFizz->buzz();
auto autoFizz = container.get<Fizz>(symbols::autoFizz);
autoFizz.buzz();
auto autoFizzUnique = container.get<IFizzUniquePtr>(symbols::autoFizzUnique);
autoFizzUnique->buzz();
auto autoFizzShared = container.get<IFizzSharedPtr>(symbols::autoFizzShared);
autoFizzShared->buzz();
Use the following to run tests:
bazel run test --enable_platform_specific_config
Note: run the example app in a similar way:
bazel run example --enable_platform_specific_config
- More compile-time checks
- Thread safety
- Resolution scope
Run python ./third_party/amalgamate/amalgamate.py -c ./third_party/amalgamate/config.json -s ./
from the root of the repository.