optional<bool> opt = false;optional<bool> has some issues which boost::optional<> avoided by saying "use boost::tribool instead" (this was seen in the original Boost review way back when). But there is currently no std::tribool nor a proposal for one. So I expect optional<bool> will be used instead in many cases.Main issue: operator bool does not return the same thing as comparison to bool. ie
// Aif (!opt) {doSomething();
}// Bif (opt == false) {doSomething();}The above 2 if-blocks are not the same. Same problem with checking against 'true' obviously.
Now, I don't really want to lose "if (opt)" doing an 'engaged' check *in general* for optional<T>, but I'm wondering if:- is it possible to make these cases ambiguous for optional<bool> only. ie instead of picking A or B it just doesn't compile.
- if it is possible, is that a palatable solution? (Note that there are alternatives for both cases - ie an explicit is_engaged() function (I think, or whatever it is called) vs an explicit dereference - "*opt == false" or check + deref.
- is it possible to make these cases ambiguous for optional<bool> only. ie instead of picking A or B it just doesn't compile.
Sure, it's possible. std::enable_if gimmicks can remove the `explicit operator bool` function if T == bool.
- if it is possible, is that a palatable solution? (Note that there are alternatives for both cases - ie an explicit is_engaged() function (I think, or whatever it is called) vs an explicit dereference - "*opt == false" or check + deref.
Absolutely not.
optional<bool> is a perfectly legitimate construct, so long as you understand what it means and how to work with it. If you don't, then you'll have problems. But it's not our job to fix that; it's your job to know what you're doing.
Let's learn the lessons of `vector<bool>`: don't change the interface to different instantiations of a template. Not unless it's because the type T flat-out doesn't support that operation.
> Maybe everyone is OK with it, but I just want to know they are *aware* of it.It was mentioned in the paper
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3527.html#rationale.bool_conversion),
just not discussed to death like some other issues.
I think people
were adequately aware of it.
bool*, unique_ptr<bool>, shared_ptr<bool> suffer from the same potential problem, "- is it possible to make these cases ambiguous for optional<bool> only. ie instead of picking A or B it just doesn't compile.
Sure, it's possible. std::enable_if gimmicks can remove the `explicit operator bool` function if T == bool.
removing the explicit operator would make A not compile, but B still compiles. I'd prefer the other way around, or neither.
removing just the 'explicit' part would probably make A compile, and make B ambiguous, but I suspect it would have other unpleasant ramifications.
- if it is possible, is that a palatable solution? (Note that there are alternatives for both cases - ie an explicit is_engaged() function (I think, or whatever it is called) vs an explicit dereference - "*opt == false" or check + deref.
Absolutely not.
optional<bool> is a perfectly legitimate construct, so long as you understand what it means and how to work with it. If you don't, then you'll have problems. But it's not our job to fix that; it's your job to know what you're doing.
I think it is our job to make APIs that are clear and usable. C++ already has enough gotchas. If coding guidelines end up saying "always explicitly use opt != nullopt instead of just i (opt)", then we have failed.
template<typename T>
void Func(const optional<T> &t)
{
if(t) {...}
}template<typename T>
void Func(const optional<T> &t)
{
if(t == false) {...}
}Let's learn the lessons of `vector<bool>`: don't change the interface to different instantiations of a template. Not unless it's because the type T flat-out doesn't support that operation.
vector<bool> is a good point. I don't think not-compiling is quite as extreme as vector<bool>, but I still agree your point has merit.The alternative is to not do conversion to bool at all (for any T), ie force it to always be explicit opt == nullopt and opt != nullopt.
I think there is similarity here to if (ptr) vs if (ptr == nullptr) and other issues with 0 converting to/from pointers, and the need for nullptr. Is optional<> making a similar mistake?
I think it is our job to make APIs that are clear and usable. C++ already has enough gotchas. If coding guidelines end up saying "always explicitly use opt != nullopt instead of just i (opt)", then we have failed.
It's not clear at all that any guidelines would ever say that.
If you in some template code that takes an `optional<T>`, why is it ever unreasonable to do this:
template<typename T>
void Func(const optional<T> &t)
{
if(t) {...}
}
This code always means the same thing no matter what T is.
Similarly:template<typename T>
void Func(const optional<T> &t)
{
if(t == false) {...}
}
will fail to compile for any T cannot be checked for equality against bools.The == operator doesn't force a contextual conversion to bool for the arguments; it will simply call the appropriate overloaded operator. The `operator==` for `optional<T>`, as defined in the standard, will check to see if `t` is disengagned. If it is, it returns false. If it isn't, it gets the T from it and performs operator== on the value being tested against. If that comparison is not supported, operator== cannot be instantiated and a compiler error results.
Again, this has well-defined behavior. For any T, it will test the internals of the optional against the value. There is therefore no expectation for this code to be testing only whether `t` is engaged or not.
So why would people suggest using `t != nullopt`?Let's learn the lessons of `vector<bool>`: don't change the interface to different instantiations of a template. Not unless it's because the type T flat-out doesn't support that operation.
vector<bool> is a good point. I don't think not-compiling is quite as extreme as vector<bool>, but I still agree your point has merit.The alternative is to not do conversion to bool at all (for any T), ie force it to always be explicit opt == nullopt and opt != nullopt.
No. This issue is not substantial enough to completely break the `optional<T>` class just because some people might be confused when `T == bool`. `optional<T>` behaves like `optional<T>` for all types T. The behavior is only confusing for `bool` if you expect it to behave differently.
This "gotcha" is a misunderstanding of concepts, not a misunderstanding of implementation. And we should not break a class's interface because someone might misunderstand the concept of what it means for a boolean to be optional.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
On Sep 2, 2013 4:48 AM, "Andrzej Krzemieński" <akrz...@gmail.com> wrote:
> The "mixed" comparison (between optional<T> and T) is a natural consequence of allowing the implicit construction of optional<T> from T (the comparison then works immediately and one would have to artificially "poison" the rel-ops).
I agree. However, I don't think the explicit bool
operator is natural. opt.empty() looks less
confusing IMHO. 100% copy of a pointer-like
interface is not needed. For example, iterator is
also pointer-like, but it has no such interface.