A semanic typedef is a kind of "strong typedef" that prevents implicit
conversion between itself and its underlying type. But rather than a
straight typedef of the base type with all operators available, a
semantic typedef allows the new type to choose the operators available
to it, increasing type safety.
An example:
// It doesn't make sense to add two CacheLineSize objects together, so // don't define add-assignment. struct CacheLineSize : public SemanticTypedef<CacheLineSize, unsigned>, : public EqualityCompare<CacheLineSize>, : public LessThanCompare<CacheLineSize> { using SemanticTypedef::SemanticTypedef; }; CacheLineSize ASize(32); CacheLineSize BSize(64); assert(ASize < BSize); static_assert(!std::is_convertible<decltype(ASize), UnderlyingType<decltype(ASize)>>::value, "Converted CacheLineSize to its underlying type!"); static_assert(!std::is_convertible<UnderlyingType<decltype(ASize)>, decltype(ASize)>::value, "Converted underlying type to CacheLineSize!");
This commit defines the basic SemanticTypedef class along with classes
to make the most common operators available: ==, <, >=, =, +=, &&, ||,
!, << (output streaming).
I know this has been discussed on the thread, but I feel obligated to point out that there is already precedent for using the term "strong typedef" for this kind of thing: LLVM_YAML_STRONG_TYPEDEF. Might not matter if the goal is to eventually replace LLVM_YAML_STRONG_TYPEDEF with this, but otherwise, it would be nice to maintain consistent naming within the project.