How to represent template-based strong ID types, type aliases, and data structures in a UML class diagram?

4 weeks ago 30
ARTICLE AD BOX

I am creating a UML class diagram for a C++ project and would like to correctly represent strongly typed identifiers implemented via templates and type aliases, as well as plain data structures (struct) used as domain objects.

In the code, identifiers are implemented using a tag-based template to achieve type safety:

template <class Tag, class Rep = std::uint32_t> class Id { // some fields }; struct AxisIdTag {}; struct RunIdTag {}; struct ReportIdTag {}; struct RecordIdTag {}; using AxisId = Id<AxisIdTag, std::uint8_t>; using RunId = Id<RunIdTag, std::uint32_t>; using RecordId = Id<RecordIdTag, std::uint64_t>; using ReportId = Id<ReportIdTag, std::uint32_t>;

There are also regular domain types such as enumerations and data structures:

enum class ErrorCode { // some fields }; struct Error { ErrorCode code{}; std::string summary; std::optional<std::string> details; std::optional<AxisId> axisId; std::optional<RunId> runId; std::chrono::system_clock::time_point timestamp; };

Goal of the diagram

The goal of the class diagram is not to reflect C++ syntax one-to-one, but to communicate design intent:

that AxisId, RunId, etc. are distinct domain identifiers, that they are all based on a common Id<Tag, Rep> abstraction, that type safety is an intentional part of the design, and that some types (such as Error) are intended to be data carriers / value-like domain objects.

I understand that UML does not have a direct notion of C++ using aliases or a dedicated struct construct, and that some of these elements are implementation details. However, I would like the diagram to express the conceptual model as accurately as possible.

Question

What is the idiomatic or commonly accepted way to represent the following in a UML class diagram?

Template-based strong ID types such as Id<Tag, Rep> Type aliases like AxisId, RunId, etc. Plain data structures (struct) that primarily act as immutable or semi-immutable data carriers

For example:

Should Id<Tag, Rep> be shown as a template class with template bindings? Should AxisId, RunId, etc. be modeled as template specializations, stereotypes (e.g. <<alias>>), or omitted and documented via notes? Should struct Error be modeled exactly like a UML class, or annotated with a stereotype such as <<struct>> or <<value object>>, <<data type>>? Is there a preferred way to balance clarity of the domain model against overloading the diagram with C++-specific implementation details?

For reference, here is part of the diagram I am currently working with: image / PlantUML on pastebin

I would appreciate guidance on whether this approach reasonably communicates the intended design, and what alternatives might be clearer or more idiomatic in UML.

Read Entire Article