Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 1999-12-14 15:01:58


John Maddock wrote on 12/14/99 7:59 AM
>Howard, Steve -
>
>OK here's a first draft of the "fundamentals",

Overall, looks real good. Specific comments below.

>Outstanding issues:
>
>Builder 4 has some problems with some of the cv-traits stuff (but it seems
>to work with gcc)

Metrowerks is having trouble in this department too. Specifically
remove_const<int*const> is failing. I've sent a note to our front end
compiler engineer asking him about this. I don't claim to fully
understand chapter 14 so I have no comment on whether this represents our
compiler bug, or a remove_const bug. Though if gcc is handling it, it's
likely a compiler bug. I can work around the problem with these
additional specializations (and similarly for the other remove_xxx):

template <typename T>
struct remove_const<T*>
{
   typedef T* type;
};

template <typename T>
struct remove_const<T* const>
{
   typedef T* type;
};

template <typename T>
struct remove_const<T* volatile>
{
   typedef T* type;
};

template <typename T>
struct remove_const<T* const volatile>
{
   typedef T* type;
};

>I've added macro hooks for built-in compiler support if should become
>available.

If you didn't do this, I was going to suggest it. Great!!

>many of your cv-modified specialisations aren't necessary - cv-modifiers
>after a reference may not be allowed (gcc rejects this anyway I think),

I was surprised our compiler accepted these too. But it did, and even
specialized on them. After reading 3.9.3 it seems to me that they are
legal beasts. Though I've never seen one before, can't think of any use
whatsoever for them, and am not surprised if no other compiler allows
them. Whether or not such a construct is necessary or not is not that
interesting to me anyway. I'm excited about the _interface_ that we're
developing here, and its ability to handle anything a given compiler can
throw at it.

>cv-modifiers prior to a *,& or [] are unnecessary - a <T*> partial
>specialisation will also catch things like "const int*" - in this case T =
>const int.

Agreed. Didn't think I did that, but if I did I was incorrect.

>However your type_traits::class_type enumerated value could be
>hard to get right, without compiler support, I'll have to ponder on that...

I don't think I want my type_traits::class_type enumerated value. The
separates seem to do the same thing with just slightly different syntax.
But I do want all the functionality provided by the enumerated value (see
below).

>BTW there is a problem with is_empty and hence compressed_pair: it looks as
>though on compilers with 8-byte alignment, that empty structs take up
>8-bytes - so "twinning" an empty struct with an int doesn't have as much an
>effect as you may think it would - this is also why Steve's is_empty didn't
>work on Builder 4.

Hmm... Metrowerks choked on is_empty as you have it. Complained about
the illegal use of an incomplete class at:

   static const bool value = (sizeof(t) == sizeof(t2));

I worked around it by moving t and t2 to namespace scope.

   static const bool value = (sizeof(empty_helper_t<T>) ==
sizeof(empty_helper_t2<T>));

Not sure if that represents a compiler bug or not, but I'm leaning toward
not a compiler bug.

Suggestions:

is_fundamental_type seems too course to me. I would like to be able to
tell integral types from floating point types. I would also like for cv
qualified "fundamental_types" to answer the same as cv unqualifed
fundamental_types: is_integral<int>::value == is_integral<const
int>::value == true. (same comment for is_void, is_array, and if the
silly compiler supports cv qualified references, is_reference too). I
see is_pointer already works for all cv-qualified versions, good!

I don't mind having extensions such as long long being distinguishable
from standard types like long, but I would also like long long to answer
yes to is_integral. Perhaps long long could also answer yes to
is_extension?

The implementation of is_fundamental_type (or is_builtin_type) really
seems to me to answer is_arithmetic (3.9.1, para 8). is_scalar might be
another useful query (3.9, para 10). The standard uses the word
"fundamental" to refer to the union of void types and arithmetic types
(which might also be a useful query).

I don't think that member_pointers should answer yes to is_pointer.
According to 3.9.2 they fall under a different category, and the use of
the word "pointer" is simply overloaded. I would like to be able to
distinquish between pointers and member pointers.

I would like to see an is_union, even though like is_enum it will take
compiler support to implement. And then is_empty will need to take that
into account since unions can be empty too (don't ask me what you would
__do__ with an empty union! :-) ).

There is some inconsistency in the naming convention in that sometimes
"_type" is appended to the query and sometimes not. I would drop "_type"
altogether:

// atomic types
is_integral
is_floating
is_void
is_array
is_pointer
is_reference
is_enum
is_class
is_union
is_member_pointer
// type categories
is_arithmetic (is_integral || is_floating)
is_fundamental (is_void || is_arithmetic)
is_scalar (is_arithmetic || is_pointer || is_enum ||
is_member_pointer)
is_compound (not is_fundamental)
is_object ? (not is_void && not is_reference) (3.9, para 9)

Nice test set up.

I think you've got a really good first draft here. I don't mind
implementing my own suggestions (don't mind someone else doing that
either), but I'm not doing that for now as I wanted to see other's
reactions as well before we roared ahead.

-Howard


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk