Awesome
<a href="http://www.boost.org/LICENSE_1_0.txt" target="_blank"></a> <a href="https://github.com/boost-ext/di/releases" target="_blank"></a> <a href="https://github.com/boost-ext/di/actions/workflows/build.yml" target="_blank"></a> <a href="https://codecov.io/gh/boost-ext/di" target="_blank"></a> <a href="http://github.com/boost-ext/di/issues" target="_blank"></a> <a href="https://godbolt.org/z/5qTKhf"></a>
[Boost::ext].DI
Your C++14 one header only Dependency Injection library with no dependencies
<p align="center"><a href="https://www.youtube.com/watch?v=yVogS4NbL6U"><img src="doc/images/di_concept.png" alt="Dependency Injection"/></a></p>Quick start
Download
[Boost::ext].DI requires only one file. Get the latest header here!
Include
#include <boost/di.hpp>
namespace di = boost::di;
Compile
- GCC/Clang
$CXX -std=c++14 -O2 -fno-exceptions -fno-rtti -Wall -Werror -pedantic-errors file.cpp
- MSVC
cl /std:c++14 /Ox /W3 file.cpp
Quick guide - Create object graph
class ctor {
public:
explicit ctor(int i) : i(i) {}
int i;
};
struct aggregate {
double d;
};
class example {
public:
example(aggregate a, const ctor& c) {
assert(87.0 == a.d);
assert(42 == c.i);
};
};
int main() {
const auto injector = di::make_injector(
di::bind<int>.to(42),
di::bind<double>.to(87.0)
);
injector.create<example>();
}
<p align="center">
<table>
<tr>
<th></th>
<th>Clang-3.8</th>
<th>GCC-6</th>
<th>MSVC-2015</th>
</tr>
<tr>
<td>Compilation Time</td>
<td>0.102s</td>
<td>0.118s</td>
<td>0.296s</td>
</tr>
<tr>
<td>Binary size (stripped)</td>
<td>6.2kb</td>
<td>6.2kb</td>
<td>105kb</td>
</tr>
<tr>
<td>ASM x86-64</td>
<td colspan="3">
<pre><code>
xor eax, eax
retq
</code></pre>
</td>
</tr>
</table>
</p>
Quick guide - Bind interfaces
struct interface {
virtual ~interface() noexcept = default;
virtual int get() const = 0;
};
class implementation : public interface {
public:
int get() const override { return 42; }
};
struct example {
example(std::shared_ptr<interface> i) {
assert(42 == i->get());
}
};
int main() {
const auto injector = di::make_injector(
di::bind<interface>.to<implementation>()
);
injector.create<std::unique_ptr<example>>();
}
<p align="center">
<table>
<tr>
<th></th>
<th>Clang-3.8</th>
<th>GCC-6</th>
<th>MSVC-2015</th>
</tr>
<tr>
<td>Compilation Time</td>
<td>0.102s</td>
<td>0.118s</td>
<td>0.296s</td>
</tr>
<tr>
<td>Binary size (stripped)</td>
<td>6.2kb</td>
<td>6.2kb</td>
<td>105kb</td>
</tr>
<tr>
<td>ASM x86-64 (same as `make_unique<example>`)</td>
<td colspan="3">
<pre><code>
push %rbx
mov %rdi,%rbx
mov $0x8,%edi
callq 0x4008e0 <_Znwm@plt>
movq $0x400c78,(%rax)
mov %rax,(%rbx)
mov %rbx,%rax
pop %rbx
retq
</code></pre>
</td>
</tr>
</table>
</p>
Quick guide - Bind templates
template<class ErrorPolicy = class TErrorPolicy>
class simple_updater {
public:
void update() const {
ErrorPolicy::on("update");
}
};
template<class Updater = class TUpdater>
class example {
public:
explicit example(const Updater& updater)
: updater(updater)
{ }
void update() {
updater.update();
}
private:
const Updater& updater;
};
int main() {
struct throw_policy {
static void on(const std::string& str) {
throw std::runtime_error(str);
}
};
const auto injector = di::make_injector(
di::bind<class TErrorPolicy>.to<throw_policy>(),
di::bind<class TUpdater>.to<simple_updater>()
);
injector.create<example>().update();
// Terminates with an uncaught exception because of our bound error policy
}
<p align="center">
<table>
<tr>
<th></th>
<th>Clang-3.8</th>
<th>GCC-6</th>
<th>MSVC-2015</th>
</tr>
<tr>
<td>Compilation Time</td>
<td>0.102s</td>
<td>0.118s</td>
<td>0.296s</td>
</tr>
<tr>
<td>Binary size (stripped)</td>
<td>6.2kb</td>
<td>6.2kb</td>
<td>105kb</td>
</tr>
<tr>
<td>ASM x86-64</td>
<td colspan="3">
<pre><code>
xor eax, eax
retq
</code></pre>
</td>
</tr>
</table>
</p>
Quick guide - Bind concepts
struct Streamable {
template<class T>
auto requires(T&& t) -> decltype(
int( t.read() ),
t.write(int)
);
};
template<class Exchange = Streamable(class ExchangeStream)
class Engine = Streamable(class EngineStream)>
class example {
public:
example(Exchange exchange, Engine engine)
: exchange(std::move(exchange)), engine(std::move(engine))
{ }
private:
Exchange exchange;
Engine engine;
};
int main() {
const auto injector = di::make_injector(
di::bind<Streamable(class ExchangeStream)>.to<exchange>(),
di::bind<Streamable(class EngineStream)>.to<engine>()
);
injector.create<example>();
}
<p align="center">
<table>
<tr>
<th></th>
<th>Clang-3.8</th>
<th>GCC-6</th>
<th>MSVC-2015</th>
</tr>
<tr>
<td>Compilation Time</td>
<td>0.102s</td>
<td>0.118s</td>
<td>0.296s</td>
</tr>
<tr>
<td>Binary size (stripped)</td>
<td>6.2kb</td>
<td>6.2kb</td>
<td>105kb</td>
</tr>
<tr>
<td>ASM x86-64</td>
<td colspan="3">
<pre><code>
xor eax, eax
retq
</code></pre>
</td>
</tr>
</table>
</p>
Documentation
- Introduction
- Do I use a Dependency Injection already?
- Do I use Dependency Injection correctly?
- Do I need a Dependency Injection?
- STUPID vs SOLID - "Clean Code" Uncle Bob
- Do I need a DI Framework/Library?
- Manual DI - Wiring Mess (Avoid it by using [Boost].DI)
- Real Life examples?
- Why [Boost].DI?
- [Boost].DI design goals
- Articles
- Videos
- [Boost::ext].DI
- Dependency Injection In General
- Acknowledgements
- Overview
- Tutorial
- Try It Online!
- Benchmarks
- User Guide
- Examples
- Hello World
- Bindings
- Dynamic Bindings
- Forward Bindings
- Is Creatable
- Multiple Bindings
- Binding Non-owning Pointer
- Binding Templates
- Binding To Constructor
- Automatic Injection
- Constructor Signature
- Constructor Injection
- Multiple Interface
- Annotations
- Deduce Scope
- Custom Scope
- Eager Singletons
- Modules
- Modules (hpp/cpp)
- Custom Policy
- Custom Provider
- Pool Provider
- Configuration
- Polymorphism
- Inheritance
- Type Erasure
- Function
- Variant
- Templates
- Concepts
- Extensions
- FAQ
- CHANGELOG
Disclaimer [Boost::ext].DI
is not an official Boost library.