I want to use a class like this:
Instead of this:Code:Item item; if(item) { .... }
Is there a way to do this? Maybe overload an operator?Code:Item item; if(item.IsValid()) { ... }
I want to use a class like this:
Instead of this:Code:Item item; if(item) { .... }
Is there a way to do this? Maybe overload an operator?Code:Item item; if(item.IsValid()) { ... }
Read about the safe bool idiom. Besides learning about the idiom itself, take note of the author's words towards the end about when not to use it.
Look up a C++ Reference and learn How To Ask Questions The Smart WayOriginally Posted by Bjarne Stroustrup (2000-10-14)
Thank you.
If the Item was "invalid" in the first place, why was it allowed to be constructed? Maybe you should throw an exception when the item would be constructed in an invalid state, so that users don't have to perpetually wonder whether the objects they possess are valid or junk.
Code://try //{ if (a) do { f( b); } while(1); else do { f(!b); } while(1); //}
O_oRead about the safe bool idiom.
^_^
It only disallows an additional conversion in a given context. It will help, and no doubt, but it doesn't solve all the problems.Thank goodness for explicit conversion operators in C++0x.
Soma
If it doesn't solve all the technical problems, please tell me which it doesn't solve. It was designed primarily because of this very use case, and if it doesn't solve all problems, it's broken and needs to be revised.
All the buzzt!
CornedBee
"There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
- Flon's Law
Does it solve the problem that things like x < y might compile because of operator bool (there isn't any other implicit casts)?
Or that you might accidentally pass the object to a function that accepts it because it expects bool?
I might be wrong.
Quoted more than 1000 times (I hope).Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
Well it's part of their inventory:
Item is a very basic class which pretty much looks like this:Code:class Player: public Character { private: ... Item items[9]; ... };
Where ItemClass* contains the behaviour and appearance loaded from an XML file. The player might not have any item in that position at all.Code:class Item { private: const ItemClass* itemClass; int level; public: Item(const ItemClass* itemClass, int level) { this->itemClass = itemClass; this->level = level; } .... }
I suppose i could of done it like this and check if item is NULL:
...but then again i could do it the way i have it now.Code:class Player: public Character { private: ... Item* items[9]; ... };
I think it just boils down to not using the right data structure. It seems like a vector might be more suited to this task than a fixed-size array. Then when an item goes away you could just erase() it from the vector. Unless for some reason you need to have the same item always be at the same index (the player refers to them by number of something)?
At any rate what I'm seeing here is a design choice in one part of the program leaking into another part which places weird requirements on the Item class
Code://try //{ if (a) do { f( b); } while(1); else do { f(!b); } while(1); //}
If i use a vector or list it's going to screw up the item placement. I want them to be able to choose which position to put the item. They can place the item in the 8th position even if they only have one item, so it needs to support gaps in between items.
I can see how doing what you're doing now makes that simpler, but I still would recommend some other approach than providing some kind of validity check for the items. If an item can be invalid, then any code which accesses that item either has to assume its valid, or remember to check for validity before using it.
What if your inventory was a std::map<int, Item>, then the syntax is mostly the same but you don't have to keep track of which indices actually refer to valid items.
Code://try //{ if (a) do { f( b); } while(1); else do { f(!b); } while(1); //}
Yeah i was just thinking about using a map.
Reading the N2437 working paper, I would say yes. You can do neither since there must be an explicit cast of some sort. On the other hand, the Wikipedia C++0x article gives the impression that explicit conversion functions only prevent implicit secondary conversions, so I guess that phantomotap either only read the Wikipedia article, or interpreted the N2437 working paper differently (but the examples seem pretty clear to me).Originally Posted by anon
Yes, that seems like the best fit for your problem at the moment.Originally Posted by 39ster
Look up a C++ Reference and learn How To Ask Questions The Smart WayOriginally Posted by Bjarne Stroustrup (2000-10-14)
Uh... conversion operators already existed. The addition of explicit conversion operators can't have been offered to provide for this use case since you could already do that.It was designed primarily [...] needs to be revised.
Anyway, I seriously don't quite get what you are suggesting or asking. The explicit conversion operators naturally disallows this use case and any others similar to it.
The ideal implicit conversion: conversion in the face of source strongly implying that the conversion should take place while disallowing conversions in the ambiguous or dangerous case. The addition and use of explicit conversion operators effectively denies that possibility entirely. (Of course, that was the intended purpose, and as far as it goes, it works.) They do so precisely because they require explicit source.If it doesn't solve all the technical problems, please tell me which it doesn't solve.
Seriously, the addition of the explicit conversion operators effectively renames the normally offered "best practice" of 'bool some_type::is_valid()' in use from 'some_type_instance.is_valid()' to 'static_cast<bool>(some_type_instance)' or 'bool(some_type_instance)'. Now, granted, this isn't the only application, and it does solve, after a fashion, the problem of what to name a given conversion function. In this the implicit conversion operators are beautiful and a nice blessing, but only if you can actually get old hats and newbies to use them as intended.
But can you overload the given explicit conversion operator for your ranged integer class and rely on the existing, natural operators to work while still prevent the bothersome implied conversion in other constructs? No.
Absolutely. (Not that you couldn't already do that, but this certainly makes it simpler which is always nice.)Does it solve the problem that things like x < y might compile because of operator bool?
Absolutely.Or that you might accidentally pass the object to a function that accepts it because it expects bool?
O_oOn the other hand, the [...] the N2437 working paper differently.
I intended to imply "disallow an additional conversion possibility separate from other implicit conversions in a given context". (Consider what happens when the explicit form from one type gets cozy with a non-explicit conversion from the other.) I'm not sure what you inferred but I think it was the wrong thing. *shrug*
Anyway, they, the examples, look absolutely transparent to me as well; nearly there is also the "inheritance" from the current standard of the given definition for 'class X' in those same examples.
The point is, for this exact use case, users will still have to deal with implicit conversion operators because they, the explicit conversion operators, don't really solve many problems. They just make the problems appear to vanish because they require the programmer to tell the compiler exactly what to do. If I don't mind doing 'if(bool(some_instance))' the explicit operators are fine, but if I need 'if(some_instance)' I still have to do the work because I can't use the explicit operators. (I chose this example because it was what the OP asked. This is really one of the least useful and least obtrusive cases.)
I actually don't mind 'static_cast<bool>(instance)'. No, that's not quite all of it; I prefer 'static_cast<bool>(instance)'. I like unambiguous statements. I also like the constructor form of assignment. (I use 'type name(arg);' instead of 'type name = arg;'.) The thing is... most programmers will not have it. We can't even get Elysia to use the C++ casts!
Soma