template <typename… Actions>
struct lager::actions

Type used to declare contexes suporting multiple action types.


template <typename Actions = void, typename Deps = lager::deps<>>
struct lager::context

Provide some context for effectful functions, allowing them to control the event loop and dispatch new actions into the store.

A context is convertible to support “more restricted” actions. This is, if action B is convertible to action A, context<A> is convertible to context<B>, in this sense, contexes are contravariant to the action type. One can also specify multiple action types by using action<> tag. This is useful to subset actions from a variant, here is an example:

struct action_A {};
struct action_B {};
struct action_C {};
using any_action = std::variant<action_A, action_B, action_C>>;

void some_effect(context<actions<action_A, action_B>> ctx)
    if (...)

void other_effect(context<any_action> ctx)

This is a reference type and it’s life-time is bound to the associated store. It is invalid to use it after the store has been destructed. Its methods may modify the store’s underlying state.
Use action type void or empty lager::actions<> if context shall have no dispatch() method and only provide deps.

Public Types

using deps_t = Deps
using actions_t = as_actions_t<Actions>

Public Functions

template <typename Actions_, typename Deps_, std::enable_if_t< detail::are_compatible_actions_v< Actions, Actions_ > && std::is_convertible_v< Deps_, Deps >, int > = 0>
context(const context<Actions_, Deps_> &ctx)
template <typename Actions_, typename Deps_, typename Converter, std::enable_if_t< detail::are_compatible_actions_v< Actions, Actions_, Converter > && std::is_convertible_v< Deps_, Deps >, int > = 0>
context(const context<Actions_, Deps_> &ctx, Converter c)
template <typename Dispatcher, typename EventLoop>
context(Dispatcher dispatcher, EventLoop &loop, deps_t deps)
template <typename Action>
future dispatch(Action &&act) const
detail::event_loop_iface &loop() const


template <typename Ctx>
bool lager::is_empty_effect(const std::function<future(Ctx)> &v)

Heuristically determine if the effect is empty or a noop operation.

template <typename Eff>
bool lager::is_empty_effect(const Eff &v)
template <typename Deps = lager::deps<>, typename Reducer, typename Model, typename Action, typename EffectHandler, typename NoEffectHandler>
auto lager::invoke_reducer(Reducer &&reducer, Model &&model, Action &&action, EffectHandler &&with_effect_handler, NoEffectHandler &&without_effect_handler)

Invokes the reducer with the model and action and returns the resulting model. If the reducer returns an effect, it evaluates the handler passing the effect to it. This function can be used to generically handle both reducers with or without side-effects.

When effects do exist, they are evaluated after updating the model.

template <typename Actions1, typename Deps1, typename Actions2, typename Deps2>
auto lager::sequence(effect<Actions1, Deps1> a, effect<Actions2, Deps2> b)

Returns an effects that evalates the effects a and b in order.

template <typename A1, typename D1, typename A2, typename D2, typename… Effs>
auto lager::sequence(effect<A1, D1> a, effect<A2, D2> b, Effs&&... effects)
template <typename Action, typename Deps = lager::deps<>>
struct lager::effect

Effectful procedure that uses the store context.

template <typename Model, typename Action = void, typename Deps = lager::deps<>>
struct lager::result

Convenience type for specifying the result of reducers that return both a model and an effect.