At least, that's how I remember it. After that, I had to work on a project for game design and forgot about it entirely, then I went and wiped my hard drive for a RAID 0 array without backing up any of my projects (derp). Now I can't for the life of me remember how I pulled off that bit of magic, and I need it before I can get any farther with a project I'm working on. The only thing I can think of is using void pointers, which I am 100% sure isn't the way I went about doing this.
All I know is that the parent class CVarAbstract has template methods for getting and setting the contained value, and that the derived CVar class is a template class and uses that to contain its value. Anyone want to fill in the missing pieces to this puzzle?
I've seen that, but I would think that it would be either slow or resource heavy compared to what I had originally, which was only about 30 lines of code. Meh, guess I won't know until I try.
boost::any seems like way more than what I had originally. Mine wasn't as safe probably, but it was a bit easier to use and I'm pretty sure was a bit more light-weight. But the boost::any class won't be accessed constantly, so speed-wise it shouldn't be much of an issue, hopefully.
Boost has its own license, but yes, it is open source.
No way is safe; they all either limit the number of types that can be stored to a predefined set (such as in boost::variant) but are typesafe, or allow any type, but require the user to cast, and are completely un-typesafe.
It is easier to use than what you wrote above, for the simple reason that in your code, I have to:
So how do the languages such as python, that are written in c/c++ pull off their var types? They are both typesafe and from what I can tell have no predefined set of types.
Then again I haven't played much with many of the languages like that so i don't know for sure.
But in this case I'll be getting variables more often than you'd be getting them, and it's the accessing of members using C-style programming methods that annoys me. VC++ has Intellisense, and I'd like to be able to use it wherever possible to shave time on the actual coding.
Really, I'd rather not use boost::any. Don't really need a lot of what it offers, and that bulk is making for a relatively slow object compared to what I had originally. I've already made a class that just has the functionality that I need, and it was, on average, 30 times faster than boost::any. I could just use that, but it uses the same C-style method of accessing the data that boost::any has, which is a real pain since the programming style conflicts with the rest of my engine. I just need help with that part really, making Get and Set template methods of the class parent class. This is the only thing I can think of doing:
class CVarAbstract;
template <typename T>
class CVar
: public CVarAbstract
{
public:
typedeftypename T Type;
Type Val;
};
class CVarAbstract
{
public:
template <typename T>
T Get ( )
{
returnstatic_cast<CVar<T>*>(this)->Val;
}
template <typename T>
void Set ( T Val )
{
static_cast<CVar<T>*>(this)->Val = Val;
}
};
But that doesn't work because CVarAbstract isn't defined at the time it's inherited by CVar.
So what does this class do for me? Are you needing it for polymorphism or type erasure?
I'll assume so, otherwise I don't see the point (why not just make a variable of the needed
type then).
I'm going to be having a list of CVarAbstract objects which point to different resources, some may be texture handles, others may be sprite objects, so I needed a way to store them all and still be able to differentiate between their types. Hardly any different from the boost::any class from what I can tell, it just doesn't throw any exceptions.
@NGen: what does your class do if the user attempts to treat the contained data as a type that is not what
it holds or is not convertible from what it holds? Is boost::variant<> an acceptable solution?
@elega: CVarAbstract absolutely must have a virtual destructor. (Not even sure how your code above
works, since CVarAbstract has no vtable, I would think the dynamic_cast wouldn't work).
The class does nothing, the user gets an error which they'll have to debug back to the point where they cast to the wrong type. Speed is an issue, since this is for a video-game after all. I guess the best thing to do, in my opinion, feel free to say it's a bad idea, is to create an abstraction layer that would allow me to swap out boost::any for a simpler, faster, and less safe class that would be used while compiling the release version. If everything's been tested properly then casting to the wrong type shouldn't be an issue. I would be an idiot to say that you can get rid of all possible bugs and errors, but in the case that an error should arise from this I can always compile in Debug mode and attempt to recreate the error using the safer boost::any. This way I get the safety when I need it, but the speed when it's being ran by the end-user.
I would create my own class "any" inside my own namespace "my_boost" and have my any have
the exact same API as boost::any. Then make a typedef for the type that switches between
my any and boost::any depending upon compilation mode.
Abstraction is OK as long as you don't introduce (additional) virtual functions, otherwise there is
a performance hit.
(From an API standpoint, and for debuggability, I would much, much, much rather the object
throw than pretend everything is alright. The problem with your approach is it may lead to
long debug sessions as a result of crashes that occur long after the original problem, which
was that the user made a bad cast.
@jsmith: That is absolutely true. I was a bit lazy with the example :)
@NGen: If speed is your primary concern, then dynamic_cast might be a bad approach. This is avoidable if the dynamic_cast is not needed often and you generally can pass the class by CVar& reference, which is not any slower than any generic class member call.
No way is safe; they all either limit the number of types that can be stored to a predefined set (such as in boost::variant) but are typesafe, or allow any type, but require the user to cast, and are completely un-typesafe.
Check this out! I came up with something that allows any type and is typesafe!
It doesn't work if T implements operator& to do funny things.
(You need to use the boost::addressof() trick to ensure line 38
does what you want it to).