Skip to content

StrongId

Tony Van Eerd edited this page Dec 4, 2019 · 2 revisions

Source: StrongId.h

A template for making ID types that are unique types for unique uses. ie WidgetIds are not the same as EmployeeIds, and it is nice if the compiler prevents you from mixing one with the other.

class Cat { /*...*/ };
class Dog { /*...*/ };
using CatId = StrongId<std::string, Cat>;
using DogId = StrongId<std::string, Dog>;
    
void petDog(DogId dogToPet);

void incompatibleTypes()
{
    CatId mycat("whiskers");

    // this next line will give a compiler error
    // error: could not convert 'mycat'
    // from 'StrongId<[...],Cat>' to 'StrongId<[...],Dog>'
    petDog(mycat);
}

StrongId has two parts - the underlying value_type (like std::string in the above examples), and the tag_type which is a type that makes the StrongId a different type than another StrongId.

So, value_type can be any Regular type, such as int, and the tag_type doesn't even need to be a full type - a forward declaration is good enough. Even this:

using WidgetId = StrongId<int, struct WidgetTag>;

What's WidgetTag? It is a struct that isn't defined anywhere - it only exists on that line (sort of an embedded forward declaration), and C++ is fine with that! (It inherited that behaviour from C, where you always say struct Foo, remember?)

A couple of common StrongId value_types are string and int, so:

template <typename Tag = void>
using StringId = StrongId<std::string, Tag>;
template <typename Tag = void>
using IntId = StrongId<int, Tag>;

Note the use of void above. Every StrongId<T, Tag> derives from StrongId<T,void>. Yes, derives from. This is for the rare occasions where you want to handle StrongIds in a more type-erased way. But this is, typically dangerous. Just because it is there doesn't mean you should use it. (It can be dangerous because you probably/hopefully have a way to make CatIds unique among cats, and DogIds unique among dogs, but if you put them into a vector<StringId> will the IDs be unique across cats and dogs?

Clone this wiki locally