Jump to content
  • Advertisement
Sign in to follow this  
ChugginWindex

Multiple integer types without implicit casting C++

This topic is 2593 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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?

Share this post


Link to post
Share on other sites
Advertisement
"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;

Share this post


Link to post
Share on other sites

"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!

Share this post


Link to post
Share on other sites
Hidden
You could overload operator = to take an int. Also, you could overload operator = for the normal class so you can't say HandleA = HandleB.

Share this post


Link to post
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;
};

Share this post


Link to post
Share on other sites
Hidden
The problem is the compiler will cast Handle<TypeA> to int and then allow you to construct a Handle<TypeB> via the implicit int constructor call.

Handle<TypeA> h = 5; // Calls Handle<TypeA>(int)
Handle<TypeB> h2 = h; // Calls operator int() to cast h into an integer, then calls Handle<TypeB>(int)

The only solution I can think of is to remove the int() cast operator and provide a toInt() method that you call explicitly when you want to convert a Handle to an integer.

Share this post


Link to post

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!

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!