<html>
<head>
<title>N2518 Compiler Support for type_traits</title>
<style>
p {text-align:justify}
li {text-align:justify}
blockquote.note
{
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
}
ins {background-color:#FFFFA0}
del {background-color:#FFFFA0}
</style>
</head>

<body>

<h1>Compiler Support for type_traits</h1>
Document Number N2518=08-0028<br/>
2008-02-01<br/>
James Widman &lt;widman at gimpel.com&gt;<br/>

<h2>Background and Rationale</h2>
<hr>
<p>
The &lt;type_traits&gt; header [20.4 meta] assumes compiler support for
several of the trait templates.  For example, the template
std::has_trivial_assign cannot be implemented without compiler support.
Every compiler that currently provides such support does so in the form of
built-in operators that are similar in grammar to the sizeof() operator.
(E.g. in the case of has_trivial_assign<T>, there is a corresponding keyword
__has_trivial_assign which is used to form the constant expression
__has_trivial_assign(T).)  Each of the operators proposed here is used to
form a constant expression of type bool.
</p>
<p>
These operators have an odd status: they are needed in order to implement
the Standard Library, yet they are not mentioned in any part of the
current working draft.  So when someone asks whether they are part of
Standard C++, one valid answer might be "yes and no, but more importantly,
yes".  I propose we change that answer to a plain "yes" and formally adopt
them as part of the core language.  If we have a common spelling and
semantics for these operators, Standard Library implementations will be
more portable.
</p>
<p>
Additionally, we might consider changing the text of 20.4 so that the
type trait templates that require compiler support are defined in terms of
these operators.  However, such wording is not included in this version of
this proposal.
</p>
<hr>

<H2>Proposed wording changes</h2>

<P>Add the following to the table of keywords in 2.11 lex.key:</p>

<blockquote>
        __is_member_object_pointer                  <br/>
        __is_member_function_pointer                <br/>
        __is_enum                                   <br/>
        __is_union                                  <br/>
        __is_class                                  <br/>
        __is_function                               <br/>
        __is_standard_layout                        <br/>
        __is_pod                                    <br/>
        __is_empty                                  <br/>
        __is_polymorphic                            <br/>
        __is_abstract                               <br/>
        __has_trivial_default_ctor                       <br/>
        __has_trivial_copy_ctor                          <br/>
        __has_trivial_assign                        <br/>
        __has_trivial_dtor                    <br/>
        __has_nothrow_default_ctor                       <br/>
        __has_nothrow_copy_ctor                          <br/>
        __has_nothrow_assign                        <br/>
        __has_virtual_dtor                    <br/>
        __is_base_of                                <br/>
        __is_convertible                            <br/>
</blockquote>

<P>Add the following to the grammar definition of <i>unary-expression</i>
in 5.3 expr.unary p1:</p>
<blockquote> <blockquote>
        <i>unary-type-trait</i> ( <i>type-id</i> )<br>
        <i>binary-type-trait</i> ( <i>type-id</i>, <i>type-id</i> )
</blockquote> </blockquote>

<P>Add the following grammar entries:</p>
<blockquote>
    <i>unary-type-trait</i>:
    <blockquote>
        __is_member_object_pointer                  <br/>
        __is_member_function_pointer                <br/>
        __is_enum                                   <br/>
        __is_union                                  <br/>
        __is_class                                  <br/>
        __is_function                               <br/>
        __is_standard_layout                        <br/>
        __is_pod                                    <br/>
        __is_empty                                  <br/>
        __is_polymorphic                            <br/>
        __is_abstract                               <br/>
        __has_trivial_default_ctor                       <br/>
        __has_trivial_copy_ctor                          <br/>
        __has_trivial_assign                        <br/>
        __has_trivial_dtor                    <br/>
        __has_nothrow_default_ctor                       <br/>
        __has_nothrow_copy_ctor                          <br/>
        __has_nothrow_assign                        <br/>
        __has_virtual_dtor                    <br/>
    </blockquote>
    <i>binary-type-trait</i>:
    <blockquote>
        __is_base_of                                <br/>
        __is_convertible                            <br/>
    </blockquote>
</blockquote>

<P>Add the following as a subsection at the end of 5.3 expr.unary:</p>

<blockquote>
    The type trait operators each yield a constant value of type bool
    indicating whether the type operands have the trait indicated by the
    trait keyword.
</blockquote>

<blockquote>
    For types T and U, the following holds:
    <ul>
        <br/><li>
        __is_member_object_pointer(T) yields <tt>true</tt> if and only if T is a (possibly
        <i>cv</i>-qualified) pointer to a non-static data member of a class.
        </li>
        <br/><li> __is_member_function_pointer(T) yields <tt>true</tt> if and
        only if T is a (possibly <i>cv</i>-qualified) pointer to a
        non-static member function.
        </li>
        <br/><li> __is_enum(T) yields  <tt>true</tt> if and only if  T is
        a (possibly <i>cv</i>-qualified) enumeration type (7.2).

        </li>
        <br/><li> __is_union(T)  yields <tt>true</tt> if and only if  T is
        a (possibly <i>cv</i>-qualified) union (9.5),
        </li>
        <br/><li>
        __is_class(T) yields  <tt>true</tt> if and only if T is a (possibly
        <i>cv</i>-qualified) non-union class type.  [<i>Note:</i>
        <tt>__is_class</tt> yields <tt>false</tt> for union types even though
        this International Standard refers to unions as classes. <i>-- end note
        </i>]

        </li>
        <br/><li>
        __is_function(T) yields  <tt>true</tt> if and only if T is a
        non-member function type.  [ <i>Note:</i> <tt>__is_function</tt>
        yields <tt>false</tt> if T is a pointer to a function.<i>--end
            note</i>]

        </li>
        <br/><li>
        __is_standard_layout(T) yields <tt>true</tt> if and only if T is a (possibly
        <i>cv</i>-qualified) standard layout type (3.9).
        
        T shall be a complete type, an array type (possibly of unknown
        bound), or <tt><i>cv</i>-void</tt>.

        </li>
        <br/><li>
        __is_pod(T) yields <tt>true</tt> if and only if T is a (possibly
        <i>cv</i>-qualified) POD type (3.9). 
       
        T shall be a complete type, an array type (possibly of unknown
        bound), or <tt><i>cv</i>-void</tt>.

        </li>
        <br/><li> __is_empty(T)  yields <tt> true</tt> if and only if T is
        a non-union class type with no non-static data
        members other than bit-fields of length 0, no virtual member
        functions, no virtual base classes, and no base class B for which
        __is_empty(B) is <tt> false</tt>.

        T shall be a complete type, an array type (possibly of unknown
        bound), or <tt><i>cv</i>-void</tt>.
        </li>
        <br/><li>
        __is_polymorphic(T) yields <tt>true</tt> if and only if T is a
        polymorphic class (10.3).

        T shall be a complete type, an array type (possibly of unknown
        bound), or <tt><i>cv</i>-void</tt>.
        </li>
        <br/><li>
        __is_abstract(T) yields <tt>true</tt> if and only if T has a pure
        virtual function.

        T shall be a complete type, an array type (possibly of unknown
        bound), or <tt><i>cv</i>-void</tt>.
        </li>
        <br/><li>

        __has_trivial_default_ctor(T) yields <tt>true</tt> if and only if
        T is a trivial type (3.9) or a class type with a trivial default
        constructor (12.1) or an array of such a class type.

        T shall be a complete type, an array type (possibly of unknown
        bound), or <tt><i>cv</i>-void</tt>.
        </li>
        <br/><li>
        __has_trivial_copy_ctor(T) yields <tt>true</tt> if and only if 

        T is a trivial type (3.9) or a reference type or a class type with
        a trivial copy constructor (12.8).

        T shall be a complete type, an array type (possibly of unknown
        bound), or <tt><i>cv</i>-void</tt>.
        </li>
        <br/><li> __has_trivial_assign(T)

        yields <tt>true</tt> if and only if 

        T is neither const nor a 
        reference type, and T is a 
        trivial type (3.9) or a class 
        type with a trivial copy 
        assignment operator (12.8).


        T shall be a complete type, an array type (possibly of unknown
        bound), or <tt><i>cv</i>-void</tt>.
        </li>


        <br/><li> __has_trivial_dtor(T)

        yields <tt>true</tt> if and only if 

        T is a trivial type (3.9) or a 
        reference type or a class type 
        with a trivial 
        destructor (12.4) or an array 
        of such a class type.

        T shall be a complete type, an array type (possibly of unknown
        bound), or <tt><i>cv</i>-void</tt>.
        </li>

        <br/><li> __has_nothrow_default_ctor(T)

        yields <tt>true</tt> if and only if 

        __has_trivial_default_ctor(T) is 
        true or T is a class type with a 
        default constructor that is 
        known not to throw any 
        exceptions or T is an array of 
        such a class type.

        T shall be a complete type, an array type (possibly of unknown
        bound), or <tt><i>cv</i>-void</tt>.
        </li>

        <br/><li> __has_nothrow_copy_ctor(T)

        yields <tt>true</tt> if and only if 

        __has_trivial_copy_ctor(T) is true or T is a class type with a
        copy constructor that is known not to throw any exceptions or T is
        an array of such a class type.

        T shall be a complete type, an array type (possibly of unknown
        bound), or <tt><i>cv</i>-void</tt>.
        </li>

        <br/><li> __has_nothrow_assign(T)


        yields <tt>true</tt> if and only if 

        T is neither const nor a 
        reference type, and 
        __has_trivial_assign(T)  is true 
        or T is a class type with a 
        copy assignment operator 
        taking an lvalue of type T that 
        is known not to throw any 
        exceptions or T is an array of 
        such a class type.

        T shall be a complete type, an array type (possibly of unknown
        bound), or <tt><i>cv</i>-void</tt>.
        </li>

        <br/><li> __has_virtual_dtor(T)

        yields <tt>true</tt> if and only if 

        T has a virtual destructor (12.4).

        T shall be a complete type, an array type (possibly of unknown
        bound), or <tt><i>cv</i>-void</tt>.
        </li>

        <br/><li> __is_base_of(T, U)

        yields <tt>true</tt> if and only if 

        T is a base class of U (10) without regard to cv-qualifiers or T
        and U are not unions and name the same class type without regard
        to cv-qualifiers. 
        
         If T and U are class types and are different types (ignoring
         possible cv-qualifiers) then U shall be a complete type.
        </li>

        <br/><li> __is_convertible(T, U)

        yields <tt>true</tt> if and only if 

        the following is well formed: 

        <blockquote>
        <pre>
    #include &lt;type_traits&gt;

    template &lt;class A&gt;
        typename std::add_rvalue_reference&lt;A&gt;::type
        f(); 

    U g() { return f&lt;T&gt;(); } 
            </pre>
            </blockquote>

            [ Note: This requirement gives well defined results 
            for reference types, void types, array types, and function
                types. -- end note ]<br/>

        T and U shall be complete types, array types (possibly of unknown
        bound), <tt><i>cv</i>-void</tt> or any combination thereof. 
        </li>

    </ul>
</blockquote>

<h2>Acknowledgements</h2>
<p>
Many thanks to Howard Hinnant for providing base document for this
proposal and for explaining why __is_convertible is defined the way it is.
</body>
</html>


