I'm working a lot with identifiers types to help me while debugging or managing collections of instances in my code. Previously, I had using directives as the following example code:
using AnimalId = unsigned int;
using TreeId = unsigned int;
After a while, I accidentally mixed AnimalId and TreeId in my logic, so I've decided to use structs in order to make the identifiers strong typed. To avoid code duplications, I've created a template
template <typename TypeTag, typename ValueType>
struct IdType
{
ValueType value;
// Methods for comparison and hashes
};
However, I believe there's two different ways of using this template:
// Using directive
struct AnimalIdTag {}
using AnimalId = IdType<AnimalIdTag, unsigned int>;
// Inheritance
struct TreeId : IdType<TreeId, unsigned int>;
And here is where I got in doubt. It seems both ways are valid, but there should be some differences. For example, with inheritance I can forward declare the TreeId on headers, which doesn't seem really feasible (in a painless way) with AnimalId. However, TreeId uses inheritance, and my knowledge on how inheritance and templates works "in background" is too weak to say, but it feels like there might be some hidden drawback.
Are there differences to make deciding which one to use easier? Or there's currently no drawbacks (besides being able to forward declare or not)?