# boost-ext.di compiles the first example to xor eax, eax; retq

> boost-ext.di is a single-header C++14 dependency injection library whose selling point is that its generated code is indistinguishable from hand-written construction: the README publishes the x86-64 assembly for its first example, which is two instructions. It requires no build step, and the file is fetched with a single raw URL.

**boost-ext/di** — C++14 Dependency Injection library

- Repository: https://github.com/boost-ext/di
- Website: https://boost-ext.github.io/di/
- Stars: 1,277 · Forks: 149
- Language: C++
- License: not declared
- Published: 2026-10-17 · Updated: 2026-10-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/boost-ext-di

## One header, fetched with curl

The distribution model is the first thing to understand, and it is unusual.

The library is described as a one header only Dependency Injection library with no dependencies, and the download instruction is a raw URL to `include/boost/di.hpp` on the `cpp14` branch. There is no package manager step, no submodule and no configure step.

The include is two lines:

```cpp
#include <boost/di.hpp>
namespace di = boost::di;
```

The namespace alias is not decoration. `boost::di` is a mouthful, and every example in the README uses the short form, which means your own code will too.

The compile commands the README gives are the other half of the model. For GCC and Clang:

```sh
$CXX -std=c++14 -O2 -fno-exceptions -fno-rtti -Wall -Werror -pedantic-errors file.cpp
```

The flags are a statement about the library's design. `-Wall -Werror -pedantic-errors` says the header is expected to compile clean under strict warnings, and `-fno-exceptions -fno-rtti` says it does not need either feature, which matters because a header that required RTTI could not be used in a project that disabled it. For MSVC the equivalent is `cl /std:c++14 /Ox /W3 file.cpp`.

A header-only library of this kind is a single large file that every translation unit includes, so parse time is the cost. That cost is what the next section measures, and it is why the numbers are published at all.

## The assembly is the argument, not the API

Each quick guide example in the README is followed by an identical three-row table and an assembly listing, and those listings are the actual sales pitch.

The first example builds an injector, binds `int` to 42 and `double` to 87.0, and creates an `example`. The generated x86-64 code for the whole thing is:

```
xor eax, eax
retq
```

Two instructions. The interface-binding example, where an `example` takes a `std::shared_ptr<interface>`, produces assembly the README labels as the same as `make_unique<example>`.

That comparison is the claim. A conventional DI container with runtime lookup emits a registry, a type-erased factory call and a lookup; this library emits the same code you would have written by hand. Whatever it does to resolve a binding happens at compile time.

The published numbers repeat the same three rows after every example, which is either deliberate emphasis or laziness in maintaining the documentation. Either way the numbers are old: the compilers named are Clang-3.8, GCC-6 and MSVC-2015, and the table shows compilation time of 0.102s, 0.118s and 0.296s respectively, with stripped binary size of 6.2kb for the two GCC-family compilers and 105kb for MSVC.

Read those numbers with the vintage in mind. The MSVC figure of 105kb against 6.2kb is a warning about a different toolchain, not a claim about the library, and both figures describe a single example rather than a project. What survives the ageing is the shape of the evidence: assembly, not benchmarks.

## Four kinds of binding, and the third one throws

The four quick guides cover interfaces, templates, concepts and plain values, and they escalate in difficulty.

Interface binding is the standard case. A `std::shared_ptr<interface>` parameter is satisfied by binding the interface to an implementation with `di::bind<interface>.to<implementation>()`.

Template binding handles a class template with a defaulted template parameter, and the example is a policy. A `simple_updater` template takes an `ErrorPolicy` defaulted to `TErrorPolicy`, and the injector binds a local `throw_policy` that throws. The program then calls `create<example>().update()`, and the README's comment states that it terminates with an uncaught exception because of the bound error policy. That is a deliberately alarming example, chosen to show that a policy injected into a template is honoured rather than ignored.

Concept binding is the least common of the four. A `Streamable` concept is defined with a member `requires` returning `decltype` of a read and a write, and two distinct concepts are named as template parameters, `Streamable(class ExchangeStream)` and `Streamable(class EngineStream)`. The names attached to the concepts matter because binding a concept to a type means binding that concept with a particular name, so `di::bind<Streamable(class ExchangeStream)>.to<exchange>()` binds one and `Engine` binds another.

The plain-value case from the first guide is the trivial one, binding `int` to 42 and `double` to 87.0.

Across all of them the shape is the same: an injector is a compile-time list of bindings, and `create<T>` is the only operation you perform against it.

## The example directory is the feature list

The `example/` directory in the repository root is named file by file, and reading those names is the most efficient way to understand what the library can do that the README does not show.

There are `automatic_injection.cpp` and `constructor_injection.cpp`, which are the two ways a dependency can arrive. `constructor_signature.cpp` suggests inspecting a constructor to decide what to inject. `annotations.cpp` implies that annotations are supported, and given the C++14 baseline that would be an extension rather than a language feature.

There is `is_creatable.cpp`, which is the trait that answers whether a type can be constructed from a given set of bindings before you try.

Scope is the category with the most files, and it is where a DI library is easiest to get wrong. `custom_scope.cpp`, `deduce_scope.cpp` and `eager_singletons.cpp` cover lifetime management, with eager singletons being the case where instances are created at injector construction rather than on first use.

Bindings have their own cluster: `bindings.cpp`, `multiple_bindings.cpp`, `multiple_interfaces.cpp`, `dynamic_bindings.cpp`, `fwd_bindings.cpp`, `bind_to_constructor.cpp`, `bind_non_owning_ptr.cpp` and `bind_templates.cpp`. Two of those are worth pausing on. `dynamic_bindings` suggests bindings can vary at runtime, which is the one thing most compile-time DI designs cannot do. `bind_non_owning_ptr` is the library telling you it can inject a reference or raw pointer to something the injector does not own, which is the mechanism for injecting into a longer-lived object.

Configuration has `configuration.cpp` and `custom_policy.cpp`, policies have their own file, and there is `custom_provider.cpp` and `modules.cpp` with a `modules/` subdirectory for grouping bindings. There is also an `errors/` directory and a `motivation.cpp`.

The repository also has `benchmark/` and `test/` directories, plus `extension/`, `tools/`, `doc/` and a `CMakeLists.txt`, and the presence of `.clang-format` and `.clang-tidy` says the code is held to a formatting and lint configuration.

## Where this loses to constructor injection you write yourself

The honest comparison is with the pattern the README itself opens with, which asks whether you already use dependency injection.

If your classes take their dependencies as constructor parameters, you are already doing dependency injection and the library's value is lifetime management and binding reuse rather than the inversion of control. That is a real but much smaller claim, and it is the claim that decides whether you need this.

The case for it is interfaces. Once your class takes a `std::shared_ptr<interface>`, someone has to choose the implementation, and in a large codebase that choice spreads across main functions, factory functions and test fixtures. A compile-time injector centralises it and removes it from tests, which is the argument for the abstraction.

Three things argue against.

A header-only library means every translation unit parses it. The published compile times are for a single small file, and on a large codebase that cost multiplies across the build graph. Projects under continuous integration with a build time budget will feel this.

C++14 is a constraint. The concepts example uses a `requires` member with a `decltype` return, which is the library's own emulation of concepts, and the default branch is `cpp14`. A project targeting C++20 has other options that use real language features.

And the compile-time design has consequences. `dynamic_bindings.cpp` exists in the examples, which means runtime binding is possible, but the design pressure runs the other way: the zero-overhead property is exactly what you get by resolving at compile time, so features that need runtime decisions cost something.

The Boost Software Foundation licence applies, as the README badge states, which is permissive and suitable for commercial use with the notice retained. The repository's own licence field is recorded as unknown, so read the licence file rather than the badge.

On maintenance: the repository is not archived, the last push was on 2026-09-11, and the recent releases are v1.3.2 and v1.3.1 both on 2025-04-02 after v1.3.0 on 2023-05-24. The two 2025 patch releases close to each other suggest a burst of fixes rather than a steady cadence, and there is a CI badge for Linux builds and a Coveralls badge for coverage.

## Conclusion

boost-ext.di fits a C++ project that wants injectable interfaces with lifetimes managed for it and refuses to pay build time or binary size for the privilege, since the assembly evidence in the README shows the abstraction compiles away. Do not adopt it expecting reflection-based configuration, because the bindings are written in C++ as template calls and there is no runtime config file. Verify first which branch you are on, since the default branch is `cpp14` rather than `main` and the recent releases sit on the 1.3 line, and confirm your build can vendor a single large header before you commit to it.

## FAQ

### How do I install boost-ext.di?

Fetch the single header from the raw URL for include/boost/di.hpp on the cpp14 branch and vendor it. Then `#include <boost/di.hpp>` and add `namespace di = boost::di;`. There is no package manager step, no dependencies and no build configuration.

### Does boost-ext.di slow down compilation?

The README publishes compilation times of 0.102s for Clang-3.8, 0.118s for GCC-6 and 0.296s for MSVC-2015, all for the same small example file. Since the library is header-only, every translation unit parses it, so those figures scale with the size of your build rather than staying fixed.

### What does the assembly generated by boost-ext.di look like?

The README publishes the x86-64 output. The first example generates `xor eax, eax` followed by `retq`, and the interface-binding example is described as identical to what `make_unique<example>` produces, which is the evidence that the container compiles away.

### Which C++ standard does boost-ext.di require?

C++14. The compile commands use `-std=c++14` for GCC and Clang and `/std:c++14` for MSVC, and the repository's default branch is named `cpp14`. The concepts example emulates concepts with a member function returning `decltype` rather than using C++20 language support.

### Can boost-ext.di manage object lifetimes and scopes?

Yes, and the examples directory names the features: custom_scope.cpp, deduce_scope.cpp and eager_singletons.cpp cover lifetime management, with eager singletons created at injector construction rather than on first use.

### What license is boost-ext.di released under?

The README carries a Boost Software Foundation Licence badge. The repository's licence field is recorded as unknown, so read the licence file rather than relying on the badge.

## Sources

- [boost-ext/di on GitHub](https://github.com/boost-ext/di)
- [Issues](https://github.com/boost-ext/di/issues)
- [Project website](https://boost-ext.github.io/di/)
- [README](https://github.com/boost-ext/di/blob/cpp14/README.md)
- [Releases](https://github.com/boost-ext/di/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/boost-ext-di
