I want to create different types that are uint32_t but are different from compilers perspective -- they can only be compared and assigned to a value of the exact same type. Here is a sample code that I want to achieve:
TextureResourceId t1 = 1000, t2 = 2000;
PipelineResourceId p1 = 1000, p2 = 2000;
BufferResourceId b1 = 1000, b2 = 1000;
if (t1 == t2) // OK!
if (t1 == p1) // Compiler error!
if (t1 == b1) // Compiler error!
I know that I can do some preprocessor magic to achieve this:
#define CREATE_RESOURCE_ID(NAME) \
class NAME { \
public: \
NAME(uint32_t value_): value(value_) {} \
bool operator==(const NAME &rhs) { return value == rhs.value; } \
private: \
uint32_t value; \
};
CREATE_RESOURCE_ID(TextureResourceId);
CREATE_RESOURCE_ID(BufferResourceId);
CREATE_RESOURCE_ID(PipelineResourceId);
int main() {
TextureResourceId tex1(1000), tex2(2000);
BufferResourceId buf1(1000);
PipelineResourceId pip1(1000);
if (tex1 == tex2) {}
if (buf1 == tex1) {}
if (tex1 == pip1) {}
return 0;
}
But I would like to know if there is a more C++'y way of doing this (e.g with inheritance or some kind of syntax with enum classes)
You can create a templated archetype and make type-tagged versions of that.
I made this a while back and haven't used it yet, so no testing, but I think the idea should be sound:
template<typename Type, typename Number>
class typed_id
{
public:
explicit typed_id(Number n): n(n) {}
typed_id(typed_id const& id): n(id.n) {}
typed_id& operator=(typed_id const& n) { this->n = n.n; return *this; }
bool operator<(typed_id id) const { return this->n < id.n; }
bool operator>(typed_id id) const { return this->n > id.n; }
bool operator==(typed_id id) const { return this->n == id.n; }
bool operator!=(typed_id id) const { return this->n != id.n; }
private:
Number n;
};
// tag types to differentiate each
// instantiation of the archetype
struct TextureResourceIdTag{};
struct PipelineResourceIdTag{};
struct BufferResourceIdTag{};
// actual types
using TextureResourceId = typed_id<TextureResourceIdTag, std::size_t>;
using PipelineResourceId = typed_id<PipelineResourceIdTag, std::size_t>;
using BufferResourceId = typed_id<BufferResourceIdTag, std::size_t>;
int main()
{
TextureResourceId t1{1000};
TextureResourceId t2{2000};
PipelineResourceId p1{1000};
PipelineResourceId p2{2000};
BufferResourceId b1{1000};
BufferResourceId b2{2000};
if (t1 == t2) {} // OK!
if (t1 == p1) {} // Compiler error!
if (t1 == b1) {} // Compiler error!
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With