Skip to main content
gamedev.net
🔒 Locked

Multiple integer types without implicit casting C++

Started by ChugginWindex 6 replies 1.7k views
Original Post
ChugginWindex
ChugginWindex
So question first, then background: Is there a way I'm not aware of in C++ to have two types defined that cannot be implicitly cast to eachother, but CAN be implicitly treated as integers?

I'm doing a handle-based resource management system in a project and I'm trying to come up with a clever way to get handle generation to be unique and avoid conflicts. Basically if I have two resources A and B, and resource managers ResourceManagerA and ResourceManagerB, I'd like to be able to generate unique handles for each instance in each type. The route I'm going right now is to have a shared integral counter in the ResourceManager base class that is incremented when ANY manager requests a new handle. This works, but obviously if for some reason two resources have the same handle, they could be used incorrectly. An easy example is how I'm wrapping OpenGL's texture handles. The manager requests OpenGL to generate a new texture handle instead of using the shared counter in the base ResourceManager class for that, so there's a discontinuity there and potentially multiple handles with the same integral representation could be made. If I had a way to say "type HandleA is an integer, and type HandleB is an integer, but casting a HandleB to a HandleA will fail at compile-time" that would be perfect...I just don't know how to do it. I'm thinking perhaps using bitfields would work?
Antheus
Antheus
"type HandleA is an integer, and type HandleB is an integer, but casting a HandleB to a HandleA will fail at compile-time[/quote]
template < class ResourceManager> // just a tag
struct Handle {
Handle(); // no constructor takes an int
int(); // whatever the syntax for implicit cast
}
typedef Handle<ManagerA> HandleA;
typedef Handle<ManagerA> HandleB;
ChugginWindex
ChugginWindex

"type HandleA is an integer, and type HandleB is an integer, but casting a HandleB to a HandleA will fail at compile-time

template < class ResourceManager> // just a tag
struct Handle {
Handle(); // no constructor takes an int
int(); // whatever the syntax for implicit cast
}
typedef Handle<ManagerA> HandleA;
typedef Handle<ManagerA> HandleB;

[/quote]

Won't this sort of solution not allow me to assign integers to the handle though? At generation time they need to have an integral value, and you should be able to easily cast it to type int when you need to, but I'd like to be able to say the following:


int i = 5;
Handle<Type1> h1 = 3; //fine, setting it to just a normal integer value
h1 = i; //fine for the same reason as above
Handle<Type2> h2(4); //also fine
h1 = h2; //BAD: because Type1 and Type2 are different.
Handle<Type3> h3(h1); //BAD for the same reason

//I'm okay with the following however, because it looks virtually impossible to block given the above requirements:
Handle<Type3> = (int)h2;



This might actually be impossible, but that's why I'm asking. In the meantime I'm playing with the example you gave, so thanks for that!
SiCrane
SiCrane
An int constructor marked explicit should stop accidental creation of your handle type from ints.
GorbGorb
GorbGorb
What about this:


template< class UniqueIdentifier >
class Handle
{
public:
Handle();
Handle( int );
Handle( const Handle< UniqueIdentifier > & );

template< class OtherIdentifier >
Handle( Handle< OtherIdentifier > ) = delete;
//this will block direct construction from other Handle types

operator int() const;
};
ChugginWindex
ChugginWindex

What about this:


template< class UniqueIdentifier >
class Handle
{
public:
Handle();
Handle( int );
Handle( const Handle< UniqueIdentifier > & );

template< class OtherIdentifier >
Handle( Handle< OtherIdentifier > ) = delete;
//this will block direct construction from other Handle types

operator int() const;
};



Won't this still construction from one type to another because the compiler will simply cast one as an integer and use it as a parameter of the other's construction?

Tho I suppose coupled with an explicit constructor this could be prevented. I'll check that out, thanks!
GorbGorb
GorbGorb

Won't this still construction from one type to another because the compiler will simply cast one as an integer and use it as a parameter of the other's construction?

Tho I suppose coupled with an explicit constructor this could be prevented. I'll check that out, thanks!


No, it won't. The templated constructor is the best match for construction from other handle types, so the compiler will try to use that one. Because it is deleted (you could also just not define it if you can't use c++11), you'll get an error.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.