On Sat, Sep 26, 2015 at 7:52 PM, Andrzej Krzemienski
2015-09-25 17:37 GMT+02:00 Andrey Semashev
: However, I'm not sure I agree with your rationale on the reduced interface and possibly the compact_optional naming.
1. You chose not to provide relational operators for compact_optional because you don't know how to order 'empty' values. I think you don't have to make that decision and simply forward the call to the underlying type. I mean, you always have the stored object constructed in some state and as long as it implements operators you can always use them.
So this is a trade-off between convenience/expressiveness and the potential to detect unintended semantics at compile-time. If there is sufficient argumentation in favor of adding them, I can always do it. As Rob says, this can also be encoded in the policy.
It can, but I really don't see the reason for it. Can you give an
example where operators defined for type T are not sensible to
compact_optional
2. compact_optional does not provide direct assignment of the values of the stored type, requiring to manually construct a compact_optional-wrapped value. To me, this is too cumbersome to use while I don't see any wins from this restriction. Besides more typing, this essentially requires to use a typedef to declare and use the compact_optional variable.
Are you proposing a member function like opt.store_raw_value(v); ?
No, I was suggesting to allow assignment of values of type T (i.e. "opt = v;"). Having a named function like store_raw_value reduces the need in the typedef but the syntax should still be simpler. You may object that this allows the assignment to make the opt object empty (or null, or singular - not sure what terminology you prefer). This may seem counterintuitive at first glance, but only as long as you treat the type as another flavor of optional<>, which is incorrect and is one reason why the name should be changed. What compact_optional really is is just a wrapper that allows to easily distinguish a special value of the governed object from all other values, and in that light there's nothing wrong if assigning this special value to the wrapper makes it singular. Analogously, there's nothing wrong with assigning a nullptr to a pointer.
I am not particularly tied to name compact_optional. I can be persuaded to rename it. On the other hand, I am not in favor of any names containing "null". I am not an English speaker, but no me "null" sounds like "numeric value zero", which makes sense for the pointer, but not for something that just is not. Maybe "singular" or "special".
Well, I'm not a native speaker but AFAIK null does literally mean zero in English. However, in the programming domain I don't see null as something that is necessarily equivalent to a zero value. It's more like a 'special value' to me. E.g. in databases null is a special value that has no connection to zero at all. Even in C++ null pointers are not required to have zero value as the underlying implementation. But I'm not insisting on nullable<>. There's also a close alternative of nilable<>. Singular is the characteristic of a particular value, not the type or range of values, so it's difficult to compose a name from it (I believe, 'singularable' is not a word). Special is too generic, IMHO. We can go a different way: nav_adapter<> (where nav stands for not-a-value) or singular_adapter<>. Although I like it less than nullable.
5. A suggestion: add evp_zero and evp_empty policies. The first uses literal zero as the special value and can be used with numeric (integer and fp) and pointer types. The second uses a default constructed value as the magic value and a member empty() function to test for magic value. This could be useful with containers, strings and ranges.
Agreed on evp_empty, but I fail to see the advantage of evp_zero over the already existing evp_value_init. The later uses the value initialized T, which already is zero for ints, floats and pointers. Or do you expect the comparison to literal 0 to be faster?
Oh, it didn't occur to me until your reply that evp_value_init already covers the evp_zero use cases. Ok, good, no need for evp_zero.