Boost logo

Boost :

From: Aleksey Gurtovoy (agurtovoy_at_[hidden])
Date: 2002-10-24 04:41:16


Sebastien Martel wrote:
> >
> > template< typename T, typename = T>
> > struct is_incomplete
> > {
> > BOOST_STATIC_CONSTANT(bool, value = true);
> > };
> >
> > template< typename T >
> > struct is_incomplete<
> > T
> > , typename identity_if< T, sizeof(T) >::type
> > >
> > {
> > BOOST_STATIC_CONSTANT(bool, value = false);
> > };
> >
> For an incomplete type, isn't sizeof undefined (standard
> 5.3.3 par. 1) ?

Nope; unless explicitly specified, "shall not" means that a diagnostic is
required.

Now, there are certain contexts where certain diagnostic can be suppressed -
for example, if the offending construct was formed in the process of
function template argument deduction (14.8.2), or in the process of matching
of class template partial specializations (14.5.4.1), which is defined in
terms of the former.

For instance, references to void are ill-formed (8.3.2 para 1), but
"provoking" the compiler to create one during function template argument
deduction process doesn't do any harm:

    typedef char (&no_tag)[1];
    typedef char (&yes_tag)[2];

    template< typename T > struct wrap;
    template< typename T > no_tag is_void_test(wrap<T&>*); // here
    template< typename T > yes_tag is_void_test(...);

    template<
          typename T
>
    struct is_void
    {
        BOOST_STATIC_CONSTANT(bool
            , value = sizeof(is_void_test<T>(0)) == sizeof(yes_tag)
            );
    };

    BOOST_STATIC_ASSERT(is_void<void>::value);
    BOOST_STATIC_ASSERT(!is_void<int>::value);

As it was pointed out by Richard Smith
(http://groups.google.com/groups?q=richard%40ex-parrot.com+type_fwd&hl=en&ie
=ISO-8859-1&oe=ISO-8859-1&selm=1011126576.17796.0.nnrp-02.3e31d362%40news.de
mon.co.uk&rnum=1), the same applies to matching of class template
specializations:

    template< typename T1, typename T2 >
    struct project1st
    {
        typedef T1 type;
    };

    template<
          typename T
        , typename U_ = T
>
    struct is_void
    {
        BOOST_STATIC_CONSTANT(bool, value = true);
    };

    template< typename T >
    struct is_void<
          T
        , typename project1st<T,T&>::type // 'void&' is ill-formed,
                                          // but no diagnostic is issued
>
    {
        BOOST_STATIC_CONSTANT(bool, value = false);
    };

    BOOST_STATIC_ASSERT(is_void<void>::value);
    BOOST_STATIC_ASSERT(!is_void<int>::value);

My original 'is_incomplete' trait implementation uses the partial
specialization form because although in theory there is very little, if any,
difference between the semantics and outcome of both techniques, in practice
all the compilers I have access to choke on this:

    template< typename T1, typename T2 > struct is_incomplete_;
    template< typename T > no_tag is_incomplete_test(
        is_incomplete_< T, typename identity_if< T, sizeof(T) >::type >*
        );

    template< typename T > yes_tag is_incomplete_test(...);

    template<
        typename T
>
    struct is_incomplete
    {
        BOOST_STATIC_CONSTANT(bool
            , value = sizeof(is_incomplete_test<T>(0)) == sizeof(yes_tag)
            );
    };

but some manage to handle an equivalent partial specialization code, at
least if they are given a little hint, namely 'identity_if<T,0>'
specialization:

    template< typename T, int >
    struct identity_if
    {
        typedef T type;
    };

    // hack, shouldn't be needed
    template< typename T >
    struct identity_if<T,0>
    {
        typedef identity_if<T,0> type;
    };

    template<
          typename T
        , typename U_ = T
>
    struct is_incomplete
    {
        BOOST_STATIC_CONSTANT(bool, value = true);
    };

    template< typename T >
    struct is_incomplete<
          T
        , typename identity_if< T, sizeof(T) >::type
>
    {
        BOOST_STATIC_CONSTANT(bool, value = false);
    };

Aleksey


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