← Browse

@romanpauk/dingo

A

Dependency Injection Container for C++, with DI, next-gen and an 'o' in a name.

instructionscodex

Install

agr install @romanpauk/dingo --target codex

Writes 1 file into AGENTS.md, pinned to git-4a2df34d.

  • AGENTS.md

Document

Quality Gate

Before finishing a non-trivial change, run the repository quality gate:

cmake --build build -t check

This target verifies C++ formatting and Markdown formatting. On non-Windows builds it also runs clang-tidy through check-tidy; Windows skips clang-tidy. Do not wire it into the default build; it is an explicit validation target for agents, local review, and CI.

Run clang-tidy directly when you want only static-analysis coverage:

cmake --build build -t check-tidy

This target requires DINGO_EXAMPLES_ENABLED=ON so clang-tidy can analyze real example translation units for this header-only library.

C++ formatting is pinned to clang-format 21 from the locked uv development environment. If the local system formatter differs, configure CMake with the locked executable:

cmake -S . -B build -DDINGO_DEVELOPMENT_MODE=ON \
  -DDINGO_CLANG_FORMAT_EXE="$(uv run --locked python -c 'import shutil; print(shutil.which("clang-format"))')"

For any C++ source or header edit, format before verification:

cmake --build build -t format
cmake --build build -t check-format

If the build directory has not been configured, configure a development build first:

cmake -S . -B build -DDINGO_DEVELOPMENT_MODE=ON

If the quality gate fails because of files unrelated to the current change, do not ignore the failure. Either fix the stale formatting as part of the change or call out the blocker explicitly in the final update.

Repository README

Describes romanpauk/dingo as a whole, which may contain artifacts other than this one. Where this artifact had no useful description of its own, its summary was taken from here.

Dingo

Dependency Injection Container for C++, with DI, next-gen and an 'o' in a name.

Dingo builds object graphs from ordinary C++ types with runtime or compile-time registration. Scopes and storage policies control ownership explicitly, and user types stay free of framework macros or base classes.

Resolution applies supported ownership and interface conversions automatically, so one registration can satisfy references, pointers, smart pointers, and interface lookups when the selected storage and scope allow it.

Tested with:

  • C++17, C++20, C++23, C++26
  • GCC 13-15
  • Clang 18-20
  • Visual Studio 2022, 2026

Build

Runtime Registration

Runtime registration uses container<> with registrations added through register_type<...>(), which fits graphs assembled by ordinary control flow.

Example code included from examples/container/quick_runtime.cpp:

// User types do not need Dingo-specific base classes or macros.
struct A {
  A() = default;
};
struct B {
  B(A &, std::shared_ptr<A>) {}
};
struct C {
  C(B *, std::unique_ptr<B> &, A &) {}
};

container<> container;
// A and B are shared, so every resolution reuses the same instances.
container.register_type<scope<shared>, storage<std::shared_ptr<A>>>();
container.register_type<scope<shared>, storage<std::unique_ptr<B>>>();

// C is unique, so every resolve<C>() creates a fresh C.
container.register_type<scope<unique>, storage<C>>();

// Constructor arguments are resolved recursively, including ownership
// conversions from the registered storage forms.
C c = container.resolve<C>();

struct D {
  A &a;
  B *b;
};

// Construct an unmanaged object using dependencies from the container.
D d = container.construct<D>();

// Or invoke a callable with resolved arguments.
D e = container.invoke([&](A &a, B *b) { return D{a, b}; });

Compile-Time Registration

Compile-time registration uses bindings<...> with container<bindings<...>> or static_container<bindings<...>>, which fits graphs known in the type system.

Example code included from examples/container/quick_static.cpp:

struct A {
  A() = default;
};
struct B {
  B(A &, std::shared_ptr<A>) {}
};
struct C {
  C(B *, std::unique_ptr<B> &, A &) {}
};

// Compile-time bindings declare the same storage and scope as runtime
// registration.
using app_bindings =
    bindings<dingo::bind<scope<shared>, storage<std::shared_ptr<A>>>,
             dingo::bind<scope<shared>, storage<std::unique_ptr<B>>>,
             dingo::bind<scope<unique>, storage<C>>>;

container<app_bindings> container;
// Resolution still uses the same API.
C c = container.resolve<C>();

struct D {
  A &a;
  B *b;
};

// construct() and invoke() work with compile-time registration, too.
D d = container.construct<D>();
D e = container.invoke([&](A &a, B *b) { return D{a, b}; });

Installation

For CMake-based projects, FetchContent is the documented integration path. The project exports the dingo::dingo interface target and has no runtime dependencies.

Example code included from test/fetchcontent/CMakeLists.txt:

include(FetchContent)
FetchContent_Declare(dingo
                     GIT_REPOSITORY https://github.com/romanpauk/dingo.git
                     GIT_TAG        v0.2.0)
FetchContent_MakeAvailable(dingo)
target_link_libraries(dingo_fetchcontent_test PRIVATE dingo::dingo)

When working from a checkout, the top-level CMake project also supports add_subdirectory(...).

Documentation

  • Getting Started: installation, runtime registration, compile-time registration, resolve(), construct(), and invoke().
  • Core Concepts: registration modes, scopes, storage, arrays, variants, factories, interfaces, and multibindings.
  • Advanced Topics: indexed resolution, annotations, runtime and compile-time registration modes, nesting, RTTI, allocation, and runtime notes.
  • Architecture: registration flow, lookup shape, extension traits, and conversion rules.
  • Examples: a guided index of runnable examples in examples/.
  • Development: local development builds, repo tooling, Markdown verification, and CI container notes.
  • Motivation and History: background on how the library evolved.

Feature Summary

  • Non-intrusive registration of ordinary C++ types
  • Runtime and compile-time registration modes
  • Explicit control over lifetime and stored representation
  • Constructor deduction with explicit factory overrides when needed
  • Interface bindings and multibindings
  • Indexed and annotated resolution
  • Parent-child container nesting
  • Array support for raw arrays and smart-pointer-backed arrays
  • Explicit variant construction plus whole-variant or held-alternative resolution
  • Custom RTTI and allocator hooks
  • Extensive generated matrix tests across features, registration modes, scopes, stored types, resolved types, and containers. See the generated matrix test model.

Related Projects

For DI library comparisons, also take a look at:

Trustgrade A

  • passBody integrity

    Whether the stored document is plausibly the kind of file the artifact declares, rather than something fetched by mistake.

  • passType matchnot applicable to this artifact type

    Whether the artifact is really the kind of thing its metadata claims it is.

  • passFreshness

    How long since the source repository was last pushed to.

  • passPrompt injection

    Scans the artifact's own text for instructions aimed at your agent rather than at you.

  • passLicense

    Whether the source repository declares an SPDX license permissive enough to redistribute.

How the grade is calculated

Each check contributes 0 points when it passes, 1 when it warns, and 2 when it fails. The total maps to a letter:

  • Aevery check passed
  • Bone warning
  • Ctwo warnings
  • Dprompt injection or body integrity failed, or three warnings
  • Fone of those failed, and something else is wrong

These are automated hygiene checks, not a security audit, and not a dependency or vulnerability scan. A grade of A means nothing was flagged — not that the artifact is safe.

Versions

  • git-4a2df34dcd2d2026-08-06