Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create different types from uint32_t that are statically different?

Tags:

c++

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)

like image 491
Gasim Avatar asked Dec 31 '22 12:12

Gasim


1 Answers

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!
}
like image 142
Galik Avatar answered Jan 13 '23 13:01

Galik