Boost logo

Boost :

From: John Maddock (John_Maddock_at_[hidden])
Date: 1999-12-16 07:38:57


Howard -

>Admittedly one could do this by saying
is_integral<remove_cv<T>::type>::value. But one could also implement
has_trivial_copy using the is_const query to do the differentiation.<

I agree that we can do it either way - the two approaches appear to be
orthogonal. However I do not believe that cv-qualified types are the same
as the unqualified types:

Consider an algorithm

template <typename Iterator>
void foo(Iterator, Iterator);

and suppose that we wish to provide an internal alternative implementation
of foo for the case where Iterator is pointer - we can clearly use
is_pointer to determine this, but should this work for cv-qualified
pointers - a const or volatile pointer is a very different beast from the
unqualified version - the algorithm may work with the qualified versions
but I suspect that its more likely to be by accident than design. To put
it another way, if someone instantiates a template on a cv-qualifed type
they probably have some very specific requirements in mind which are
probably not met by most template code. Going back to foo - the author of
the algorithm is forced to choose between 4 possible checks:

is_pointer<Iterator>::value
is_pointer<remove_const<Iterator>::type>::value
is_pointer<remove_volatile<Iterator>::type>::value
is_pointer<remove_cv<Iterator>::type>::value

which makes it reasonably explicit what is actually allowed.

This approach is also consistent with existing traits classes - such as
numeric_limits, char_traits, and iterator_traits, which are not generally
specialised on cv-qualified types - for example numeric_limits<const
int>::is_specialized is false.

Having said all that, I can see the attraction in your approach - that a
type always belongs to exactly one group - I just feel that there may be
unexpected pitfalls that way - perhaps in truth there are pitfalls both
ways, whatever we must be absolutely consistent and make the docs very
clear the direction we have taken. I guess the question then is which
direction has the fewer pitfalls for the unwary?

>I'm viewing this as an implementation of 3.9, instead of a wrapper around
numeric_limits. I can imagine situations where you might want to plug a
UDT into numeric_limits (BigNum or whatever), but still might want to
differentiate BigNum from int based on the defintions in 3.9. Here it
says int is integral and BigNum is a class -- even though a
numeric_limits<BigNum> makes perfect sense. For example, I can derive
from BigNum, but I can't from int. is_empty needs that kind of
information.<

Yep, I think I would agree with that.

>I liked your consistent use of "value" for bool and "type" for typedefs.
But if we remove the trailing "_type" from (say) is_fundamental_type,
usuage looks like:

is_fundamental<T>::value

Ok, not bad, but this doesn't look too bad either:

is_fundamental<T>::type

When I read it out loud, it sounds kinda' nice. You can still tell it is
a bool because of the "is_" prefix. Just a thought...<

I don't like that, it breaks the consistency, and there are enough things
to remember already, I don't mind whether it's "is_fundamental" or
"is_fundamental_type" though.

- John.


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