stdcxx-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Martin Sebor <>
Subject Re: implementation of Unary Traits
Date Fri, 27 Jun 2008 05:04:52 GMT
Travis Vitek wrote:
> Martin Sebor wrote:
>> The implementation of Unary Traits (e.g., is_void) uses explicit
>> specialization on all four combinations of cv-qualifiers for each
>> trait (plain, const, volatile, and const volatile). I'm wondering
>> if the alternative approach of stripping the qualifiers before
>> "dispatching" to just one explicit specialization has been
>> considered. 
> That is what I had originally done.

I forgot about that.

> The only issue is that this creates a cyclic dependency between traits
> defined in <rw/_meta_cv.h> and those in <rw/_meta_cat.h>.

But only because of the __rw_add_xxx Transformation Traits. Not
because of the __rw_is_xxx Unary Traits, correct? IMO, the two
categories belong in separate headers anyway. Not just logically
but also (and mainly) because unlike the latter, I don't expect
us to be needing the former in [many] other areas of the library.

> An easy way to
> 'fix' this would be to forward declare __rw_remove_cv in
> <rw/_meta_cat.h> and then include <rw/_meta_cv.h> at the bottom, but
> this goes against our conventions. Another option was to put the
> remove-cv traits into their own header, but this went against your
> request to organize the traits in files according to some rationale.

My suggested guideline is to group traits according to how likely
they are to be used in other areas of the library. I expect the
is_cv-kind of traits to be used pervasively (in containers and
some algorithms). OTOH, I expect the add_cv ones to be used only
exceedingly rarely, if ever. Traits that are not used in other
library headers can be defined directly in <type_traits> or
grouped in implementation-specific headers according to some
other sensible criteria. I don't have a strong preference as
long as they don't get pulled in to translation units

>> The potential advantage of this approach is fewer
>> declarations, smaller translation units, and thus (presumably)
>> faster compilation.
> There has to be a balance somewhere.


> If all traits are in one file, we
> have few includes, but lots of unnecessary declarations. If we spread
> them all out, then we have few unnecessary declarations, but many
> includes. Both can _potentially_ lead to (ever so slightly) longer
> compile times in some cases and shorter ones in other cases.
> I'm definitely open to suggestions and I'm willing to make any necessary
> changes. Unfortunately any suggestion has to take the following criteria
> into consideration...
>   A. the number of trait headers should be kept to a minimum (to keep
> compile times down)
>   B. there should not be many unnecessary declarations in any header (to
> keep compile times down)
>   C. traits should be put into files according to some well defined
> rationale (to keep things organized)
> Unfortunately, I don't really see a clear path to satisfying all of the
> above requirements.

I can think of a couple of options that satisfy these. I'm not sure
how palatable I find them yet, but I might get over their (initial)
lack of appeal if the payoff is worth it. YMMV.

One is to drop the cv specializations of the __rw_is_xxx traits and
define the standard traits in terms of both remove_cv and the __rw
traits, like so:

   template <class _TypeT>
   struct is_void:
   { };

or more concisely:

   template <class _TypeT>
   struct is_void:
       integral_constant<bool, _RWSTD_IS_VOID (_TypeT)::value>
   { };

with _RWSTD_IS_VOID() being #defined like so:

   #define _RWSTD_IS_VOID(T) \
       _RW::__rw_is_void<typename _RW::__rw_remove_cv<T>::type>

All internal code would always need to use _RWSTD_IS_VOID() and
never _RW::__rw_is_void directly.

The other is to introduce an additional intermediate template for
each of the __rw_is_xxx traits to remove the cv qualifiers:

     template <class _TypeT>
     struct __rw_is_void_impl: __rw_false_type { };

     template <>
     struct __rw_is_void_impl<void>: __rw_true_type { };

     template <class _TypeT>
     struct __rw_is_void:
         __rw_is_void_impl<typename __rw_remove_cv<_TypeT>::type>
     { };

The first alternative is definitely the cheapest in terms of lines
of new code required to implement it, but I know that not everyone
is a fan of macros. The redeeming fact is that IIRC we were planning
to use the _RWSTD_IS_XXX() macros anyway, so this change shouldn't
be a problem.

The second one seems somewhat "cleaner" but I suspect adding the
additional template might cancel out the savings gained by removing
the explicit specialization.

Let me know what you think.


View raw message