Hello. I'm trying to code a card game of sorts, inspired in MTG and YGO. I've declared an enum of possible card types and a struct, which contains as an element its type. The problem arises when I need to define the elements of said struct given the type, for instance, if (card.type == creature), I'll need a shortunsignedint strength and a shortunsignedint resistance, but that wouldn't be the case if (card.type == magic). What would be a good way of doing this? I'd not like to create a struct for every card type and it would be preferable to have all types in one same struct. Thank you.
This is a case where object oriented programming would help.
If card type, such as creature, magic, ..., would be associated with a set of things they can do (methods), you can define categories of objects.
Why would you do this when you can represent everything as an enum? So the language can help you with your ideas, rather than you having to code all your ideas using integer flags. You end up with simpler and usually more reliable code that's easier to extend.
If you're you're interested in pursuing this method, then we'll need a bit more detail on what you're doing.
Kbw is correct, you are effectively writing in C which has only the crudest object support and forces you to do this by hand.
You can do it, of course.
one easy way is to add all the crap you need to the struct, so it has fields it does not need and you know which set of fields to use based off the type. It wastes a little space and is clunky, but it will get it done.
that is a little crude: a union would clean up the mess and stop wasting MOST of the memory.
looks like
1 2 3 4 5 6 7 8 9 10 11 12 13
union data //this can be a union of simple structs...
{
crittercard cc;
magiccard mc;
}
struct card
{
myenum type;
data mydata;
}
if(somecard.type == magic)
somecard.mydata.mc.whatever = hoopajoo;
but again this is fairly barbaric in c++. Barbarism has its moments, though. If you add a char array of the size of the union into the union (remember to keep this updated if you tamper with the underlying structs!!!) you can read and write that in binary as a 'card' to a file etc -- it serializes all you need automatically if you don't have any pointers or c++ containers (includes string) or anything nontrivial in the structs. It may be wise to pull your card decks from a file, so you can grow the game by adding cards without recompiling or anything.
std::variant represents a type-safe union. There is the inbuilt c/c++ union which has been 'extended' to 'sort of work' with union of C++ structs/classes etc. However there are big potential issues in doing this. That's why std::variant was introduced to 'fix' the problems using union.
Basically unless you use POD (or a simple struct composed of POD without constructor/destructor/virtual etc ) then don't use union - use std::variant.
I understand the difference between a regular union and std::variant, as well as the concept of being type safe.
What I am confused is with the terminology, "discriminated." If that boils down to "this means 'type safe'" then m'ok.
Doing a 'net search for "discriminated union" really doesn't find anything that explains it without being a load of high-falutin' gobbley-gook techno-babble to me.
Well, after flailing around, a LOT, I found this Dr. Dobb article:
What I am confused is with the terminology, "discriminated."
What distinguishes a "non-discriminated" union from a "discriminated" union is the presence of a variable that says what the union represents. This variable is called the discriminator. Unsurprisingly.
In the above code the discriminator is declared on line 11:
9 10 11 12 13 14 15 16 17 18 19 20
class card
{
card_type type; // <-- discriminator
// says whether *this represents a magic card or a creature card
union
{
creature_card creature;
magic_card magic;
};
// ...
};
Inside std::variant the discriminator is the value you get back from std::variant<T0, T1, T2>::index. It gives you 0 if it stores a T0, 1 if it stores a T1, and so on.
Would you, mbozzi, recommend using std::variant since this is C++ code
Yes. Although I think the above is reasonable, variant leads to the following code: