template <typename… Deps>
class lager::deps

Dependency passing type.

This type helps passing contextual dependencies arround. Effectively, it is a bag of statically keyed values (dependencies). You can convert between bags of dependencies, as long as the required dependencies of the target bag is a strict subset of the required dependencies of the argument bag. They idea is that a the root of your application you hold a bag with all the context you need. You pass this context around to various components, each extracting a subset of it. Components can further down pass these extracting further subsets.

Another way to look at it is that deps is basically like a struct where naming members is optional, and where you can automatically convert between structs that have attributes with the same name. In type theortical terms, this way of converting between types is called structural typing.

Here is one example of how this type might be used.

struct user_db_t {};
struct post_db_t {};

void foo(deps<dep::key<user_db, database&>, dep::opt<logger&>> d)
    database& db = d.get<user_db>();
    if (d.has<logger>()) d.get<logger>().debug("...");

void bar(deps<logger&, dep::opt<dep::key<post_db, database&>> d)
   try {
       d.get<logger>().info("", d.get<post_db>().query(...));
   } catch (missing_dependency const&) {
     // d.get<post_db>() may throw cuz it's optional

int main()
   database udb;
   database pdb;
   logger log;
   auto dependencies = deps<dep::key<user_db, database&>,
                            dep::key<post_db, database&>
                            logger&>::from(udb, pdb, log);

Deps dependency specifications for each attribute of deps.

See the contents of the namespace to see how to specify dependencies. Note that if a normal type or reference is used, a specification is generated with dep::to_spec.


template <typename… Ts>
auto lager::make_deps(Ts&&... args)

Returns a deps object containing everything passed in args. Dependencies will be stored as references only if wrapped in a std::reference_wrapper (see std::ref).


using is_spec = std::is_base_of<spec, T>
using to_spec = typename std::conditional_t< is_spec_v<T>, T, std::conditional_t<std::is_reference_v<T> || detail::is_reference_wrapper_v<T>, ref<std::remove_reference_t<T>>, val<T>>>::type

Convert T to a dependency specification. If T is a dependency specification it just returns T. If T is a reference type or a std::reference_wrapper, it results in a ref<[dereferenced T]>. Otherwise it is just a val<T>.

constexpr auto lager::dep::is_spec_v = is_spec<T>::value
template <typename Spec>
detail::spec_value<Spec> lager::dep::as(typename Spec::storage v)

Pairs value of type T with specificatio Spec

template <typename T>
struct lager::dep::fn

Modifies specification or type T to make it indirectly provided via a function.

template <typename K, typename T>
struct lager::dep::key

Modifies specification or type T to associate it with type tag K.

template <typename T>
struct lager::dep::opt

Modifies specification or type T to make it optional.

template <typename T>
struct lager::dep::ref

Specify a dependency of references to T and key T

Inherits from lager::dep::spec

Subclassed by lager::dep::ref< std::reference_wrapper< T > >

template <typename T>
struct lager::dep::ref<std::reference_wrapper<T>>

Inherits from lager::dep::ref< T >

struct lager::dep::spec

Base class that marks specification types.

Subclassed by lager::dep::ref< T >, lager::dep::val< T >

template <typename T>
struct lager::dep::val

Specify a dependency of value T and key T

Inherits from lager::dep::spec


template <typename Key, typename… Ts>
decltype(auto) lager::get(const deps< Ts... > & d)

Free standing alias for deps::get()

template <typename Key, typename… Ts>
bool lager::has(const deps<Ts...> &d)

Free standing alias for deps::has()

template <typename T>
struct lager::is_deps

Metafunction to see if something is a deps type.

template <typename… Ts>
struct lager::is_deps<deps<Ts...>>