#### Associated Characteristics and Associators

An asynchronous agent has associated characteristics that specify how asynchronous operations should behave when composed as part of that agent, such as:

- An allocator, which determines how the agent's asynchronous operations obtain memory resources.
- A cancellation slot, which determines how the agent's asynchronous operations support cancellation.
- An executor, which determines how the agent's completion handlers will be queued and run.

When an asynchronous operation is run within an asynchronous agent, its implementation may query these associated characteristics and use them to satisfy the requirements or preferences they represent. The asynchronous operation performs these queries by applying associator traits to the completion handler. Each characteristic has a corresponding associator trait.

An associator trait may be specialised for concrete completion handler types to:

- accept the default characteristic supplied by the asynchronous operation, returning this default as-is
- return an unrelated implementation of the characteristic, or
- adapt the supplied default to introduce additional behaviour required by the completion handler.

###### Specification of an Associator

Given an associator trait named[2] `associated_R`, having:

- a source value `s` of type `S`, in this case the completion handler and its type,
- a set of type requirements (or a concept) `R` that define the syntactic and semantic requirements of the associated characteristic, and
- a candidate value `c` of type `C` that meets the type requirements `R`, which represents a default implementation of the associated characteristic, supplied by the asynchronous operation

the asynchronous operation uses the associator trait to compute:

- the type `associated_R<S, C>::type`, and
- the value `associated_R<S, C>::get(s, c)`

that meet the requirements defined in `R`. For convenience, these are also accessible via type alias `associated_R_t<S, C>` and free function `get_associated_R(s, c)`, respectively.

The trait's primary template is specified such that:

- if `S::R_type` is well-formed, defines a nested type alias type as `S::R_type`, and a static member function get that returns `s.get_R()`
- otherwise, if `associator<associated_R, S, C>::type` is well-formed and denotes a type, inherits from `associator<associated_R, S, C>`
- otherwise, defines a nested type alias type as `C`, and a static member function get that returns `c`.

[2] The associator traits are named `associated_allocator`, `associated_executor`, and `associated_cancellation_slot`.