|
Boost : |
From: Daryle Walker (darylew_at_[hidden])
Date: 2001-05-02 08:40:36
on 4/30/01 2:42 AM, Aleksey Gurtovoy at alexy_at_[hidden] wrote:
> Daryle Walker wrote:
>> Version 25 of "dlw_oprs.zip" has a new trial name for the unary operator+()
>> helper class template. It has adaptations for the newest Boost release, and
>> some general improvements.
>
> IMO the new unary operator+() name - 'identity_querible' - is still
> counter-intuitive. I would suggest to go with Dave's version -
> 'unary_plusable'; it's much more easy to remember, and, as Dave said,
> accurate and consistent with the documented naming strategy; to my ears it's
> not even ugly :).
That name doesn't match the other names that well. For instance, the
template for the binary + is called "addable," not "binary_plusable." The
template is named after the operation, not the operator. The operation that
the unary + does has a name, the identity function. That's where I get the
name from. The major exceptions are "left_shiftable" and "right_shiftable,"
since their operations have no other name (that I know of).
> Some other random comments:
>
> 1) I am against including the 'unsigned_integer_convertible',
> 'signed_integer_convertible', 'float_convertible' and their composite
> operator classes into the library. First at all, I find it unnatural,
> unnecessary and unsafe for a class to define an implicit conversion
> operators in the way 'signed_integer_convertible' class template (for
> example) does it:
>
> operator signed char() const {
> return static_cast< ::boost::intmax_t >( static_cast<const T&>(*this) );
> }
> operator short() const {
> return static_cast< ::boost::intmax_t >( static_cast<const T&>(*this) );
> }
> operator int() const {
> return static_cast< ::boost::intmax_t >( static_cast<const T&>(*this) );
> }
> // etc.
>
> It's unnatural, because defining an implicit type conversion operator for
> the class is a statement of the close relationship between two types, and,
> at least for me, it's confusing and it "washes out" the semantics of the
> class, when there are too many types/classes for which such statement was
> made.
I want to be able to simulate the "unreasonable" conversions C++ allows
between all the arithmetic types.
> Taking the 'bitint<>' class template as an example ('bitint.zip' archive in
> the vault; as far as I understand, it was the main motivation for proposing
> the discussed templates into the library), when I write 'bitint<32>' I would
> expect the class to define only _one_ implicit conversion operator - on my
> platform, it would be 'operator int() const'. Also, I find it _technically_
> wrong that with current version of the class I will also get "for free"
> implicit conversion operators to 'short', 'char' etc. and can write
> something like
>
> char c = bitint<32>(100000);
>
> without getting a single warning from the compiler about data loss in my
> code (also, see below).
>
> It's also unnatural because it requires the target class to define a
> conversion to the "biggest" signed or unsigned type instead of conversion to
> the most suitable one (that in some cases can also lead to a performance
> degradation).
Some types may not be able to determine which integral type is the most
suitable, so choosing the largest is the safest option.
> It's unnecessary, because providing just one conversion operator, e.g.
> 'operator int() const':
>
> struct my { operator int() const { return 0; } };
>
> is enough for the following statements to compile successfully (except
> warnings, see below):
>
> char c = my(); // 1
> short s = my(); // 2
> int i = my();
> long l = my();
>
> It's unsafe, because the discussed templates move a dangerous code from a
> client side to the library header, thus making it look less suspicious/more
> easy to accept and, on some compilers, just turning off the diagnostics.
> Taking the above code as an example, a good compiler will issue a warning
> for the lines 1 and 2 about implicit arithmetic conversions from 'int' to
> 'short' and 'char' that can lead to a data loss, which is IMO a good thing.
> But if, instead of providing a single conversion operator to the most
> appropriate type, you decide to use 'signed_integer_convertible' class,
>
> struct my : signed_integer_convertible<my>
> { operator long() const { return 0; } };
>
> the warnings will be issued for the code in the library's header, or not
> issued at all (!) (also often you don't even have a chance to find out which
> lines in your code caused these warnings). The latter is a problem of those
> particular compilers, of course, but the main point remains - hiding
> implicit conversions, that can lead to a data loss, in the header is not a
> thing that a good library should do.
I changed the operator templates to add an explicit conversion to their
final type, avoiding those warnings.
> 2) All words in the "Use of _Concepts_" section's title are capitalized,
> despite that the very first sentence of the section says:
> "The discussed concepts are not necessarily the standard library's concepts
> (CopyConstructible, etc.), although some of them could be; they are what we
> call concepts with a small 'c'." :). I think the title should be "Use of
> _concepts_".
OK.
> 3) I remember that the name 'totally_comparable' was born as a compromise
> between my suggestion of plain 'comparable' (with which Dave was
> disagreeing) and the previous 'totally_ordered', but looking at it now, I
> think that the compromise is worse that both of the alternatives.
> Personally, I am still favor 'comparable', and we already have 'bitwise' and
> 'shiftable' as precedents :), but I can live with 'totaly_ordered' too.
> Dave?
I changed it back to "totally_ordered." In fact, it inspired me to add two
new operator helper class templates. The "partially_ordered" template
composes operator>, operator<=, and operator>= from _both_ < and ==, since
this is the safe way to compose the others if the target type doesn't have a
total ordering. (It can also work for types with a total ordering, by
"less_than_comparable" would be more efficient.) The "equivalent" template
composes operator== from < (x == y -> !(x < y) && !(y < x)).
> That's all for now. Besides the commented issues, I think the library looks
> really good and I am looking forward to see it updated!
-- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT mac DOT com
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk