template <template<typename> class Digester = std::hash, typename Storage = EmptyStorage>
class AnyId;
```
`Digester`: a template class that has one template parameter. It has a function call operator that receives one value and returns the digest of the value. The returned digest must be hashable, i.e, it must be able to be passed to `std::hash`. One of such `Digester` is `std::hash`. The parameter default value is `std::hash`.
`Storage`: a class that can be constructed with any types of values which are going to be used in `AnyId`. One of such `Storage` is `std::any` (in C++17). The parameter default value is an empty storage class that can be constructed with any types and it doesn't hold the value.
TheDigestTypeSuchAsSizeT operator() (const T & value) const {
// compute the digest of value and return the digest.
}
};
```
Note: the return type of the function call operator (here is TheDigestTypeSuchAsSizeT) must be the same for all T, it can't be different type for different T.
Return the value that's stored in `Storage`. The default `Storage` is an empty structure, so you can't get the real value from it.
If `std::any` is used as the `Storage` parameter when initializing the `AnyId` template, `getValue` returns the `std::any` thus the value can be obtained from the `std::any`.
`AnyHashableId` is an initialization of `AnyId` with the default parameters. It can be used in place of the event ID in `EventDispatcher` or `EventQueue`.
In the example code in the beginning of this document, the `eventpp::AnyId<>` can be replaced with `eventpp::AnyHashableId`.
## Comparison AnyId
`AnyId` supports `operator ==` for being used in `std::unordered_map`, and `operator <` for being used in `std::map` (which map is used depending on the policies), in `EventDispatcher` and `EventQueue`.
`AnyId` compares the digest first (the digest must be comparable).
If the `Storage` supports the operators, the values in the storage are compared. In this case, it doesn't matter if digest collides.
If the `Storage` doesn't support the operators, only the digests are compared. In this case, if digest collides, the result is in collision.
Even though `AnyId` looks smart and very flexible, I highly don't encourage you to use it at all because that means the architecture has flaws. You should always prefer to single event type, such as `int`, or `std::string`, than mixing them.
If you want to use `AnyHashableId` (aka, `AnyId<>`), don't forget to take into account of the collision created by `std::hash`, and be sure your event IDs don't collide with each other.
If you find there are good reasons to mix the event types and there are good cases to use `AnyId`, you can let me know.