In the first installment of "Category theory for programmers", Bartosz Milewski introduces a particular category in which objects and morphisms are thought as C++ values and C++ functions, respectively.

Instead, let us try to delineate the category in which objects are C++ types. In such a category, morphisms are *metafunctions* rather than ordinary functions. Thus, the identity morphisms are all representable via the following `id`

metafunction:

```
template <typename T>
using id = T;
```

We can introduce other morphisms in a similar fashion. For instance, we can come up a morphism that maps from some type `T`

to `T*`

:

```
template <typename T>
using add_pointer = T*;
```

Morphisms can be composed through a correspoding `compose`

operator, implemented as:

```
template <
template <typename> class f,
template <typename> class g
>
struct compose {
template <typename T>
using apply = g<f<T>>;
};
```

With all the elements in place, we are now in the condition to put our category at work. As an example, we can check the identity law:

```
// Identity laws
using int_ptrL = compose<id, add_pointer>::apply<int>;
using int_ptrR = compose<add_pointer, id>::apply<int>;
static_assert(std::is_same_v<int_ptrL, int_ptrR>);
```