2008-02-01

James Widman <widman at gimpel.com>

The <type_traits> 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

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.

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.

Add the following to the table of keywords in 2.11 lex.key:

__is_member_object_pointer

__is_member_function_pointer

__is_enum

__is_union

__is_class

__is_function

__is_standard_layout

__is_pod

__is_empty

__is_polymorphic

__is_abstract

__has_trivial_default_ctor

__has_trivial_copy_ctor

__has_trivial_assign

__has_trivial_dtor

__has_nothrow_default_ctor

__has_nothrow_copy_ctor

__has_nothrow_assign

__has_virtual_dtor

__is_base_of

__is_convertible

Add the following to the grammar definition of *unary-expression*
in 5.3 expr.unary p1:

unary-type-trait(type-id)

binary-type-trait(type-id,type-id)

Add the following grammar entries:

unary-type-trait:__is_member_object_pointer

__is_member_function_pointer

__is_enum

__is_union

__is_class

__is_function

__is_standard_layout

__is_pod

__is_empty

__is_polymorphic

__is_abstract

__has_trivial_default_ctor

__has_trivial_copy_ctor

__has_trivial_assign

__has_trivial_dtor

__has_nothrow_default_ctor

__has_nothrow_copy_ctor

__has_nothrow_assign

__has_virtual_dtor

binary-type-trait:__is_base_of

__is_convertible

Add the following as a subsection at the end of 5.3 expr.unary:

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.

For types T and U, the following holds:

- __is_member_object_pointer(T) yields
trueif and only if T is a (possiblycv-qualified) pointer to a non-static data member of a class.- __is_member_function_pointer(T) yields
trueif and only if T is a (possiblycv-qualified) pointer to a non-static member function.- __is_enum(T) yields
trueif and only if T is a (possiblycv-qualified) enumeration type (7.2).- __is_union(T) yields
trueif and only if T is a (possiblycv-qualified) union (9.5),- __is_class(T) yields
trueif and only if T is a (possiblycv-qualified) non-union class type. [Note:__is_classyieldsfalsefor union types even though this International Standard refers to unions as classes.-- end note]- __is_function(T) yields
trueif and only if T is a non-member function type. [Note:__is_functionyieldsfalseif T is a pointer to a function.--end note]- __is_standard_layout(T) yields
trueif and only if T is a (possiblycv-qualified) standard layout type (3.9). T shall be a complete type, an array type (possibly of unknown bound), or.cv-void- __is_pod(T) yields
trueif and only if T is a (possiblycv-qualified) POD type (3.9). T shall be a complete type, an array type (possibly of unknown bound), or.cv-void- __is_empty(T) yields
trueif 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) isfalse. T shall be a complete type, an array type (possibly of unknown bound), or.cv-void- __is_polymorphic(T) yields
trueif and only if T is a polymorphic class (10.3). T shall be a complete type, an array type (possibly of unknown bound), or.cv-void- __is_abstract(T) yields
trueif and only if T has a pure virtual function. T shall be a complete type, an array type (possibly of unknown bound), or.cv-void- __has_trivial_default_ctor(T) yields
trueif 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.cv-void- __has_trivial_copy_ctor(T) yields
trueif 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.cv-void- __has_trivial_assign(T) yields
trueif 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.cv-void- __has_trivial_dtor(T) yields
trueif 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.cv-void- __has_nothrow_default_ctor(T) yields
trueif 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.cv-void- __has_nothrow_copy_ctor(T) yields
trueif 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.cv-void- __has_nothrow_assign(T) yields
trueif 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.cv-void- __has_virtual_dtor(T) yields
trueif and only if T has a virtual destructor (12.4). T shall be a complete type, an array type (possibly of unknown bound), or.cv-void- __is_base_of(T, U) yields
trueif 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.- __is_convertible(T, U) yields
trueif and only if the following is well formed:[ Note: This requirement gives well defined results for reference types, void types, array types, and function types. -- end note ]#include <type_traits> template <class A> typename std::add_rvalue_reference<A>::type f(); U g() { return f<T>(); }

T and U shall be complete types, array types (possibly of unknown bound),or any combination thereof.cv-void

Many thanks to Howard Hinnant for providing base document for this proposal and for explaining why __is_convertible is defined the way it is.