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_pointerbinary-type-trait:
__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 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 true if and only if T is a (possibly cv-qualified) pointer to a non-static data member of a class.
- __is_member_function_pointer(T) yields true if and only if T is a (possibly cv-qualified) pointer to a non-static member function.
- __is_enum(T) yields true if and only if T is a (possibly cv-qualified) enumeration type (7.2).
- __is_union(T) yields true if and only if T is a (possibly cv-qualified) union (9.5),
- __is_class(T) yields true if and only if T is a (possibly cv-qualified) non-union class type. [Note: __is_class yields false for union types even though this International Standard refers to unions as classes. -- end note ]
- __is_function(T) yields true if and only if T is a non-member function type. [ Note: __is_function yields false if T is a pointer to a function.--end note]
- __is_standard_layout(T) yields true if and only if T is a (possibly cv-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 true if and only if T is a (possibly cv-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 true 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 false. T shall be a complete type, an array type (possibly of unknown bound), or cv-void.
- __is_polymorphic(T) yields true 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 cv-void.
- __is_abstract(T) yields true if 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 true 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 cv-void.
- __has_trivial_copy_ctor(T) yields true 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 cv-void.
- __has_trivial_assign(T) yields true 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 cv-void.
- __has_trivial_dtor(T) yields true 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 cv-void.
- __has_nothrow_default_ctor(T) yields true 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 cv-void.
- __has_nothrow_copy_ctor(T) yields true 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 cv-void.
- __has_nothrow_assign(T) yields true 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 cv-void.
- __has_virtual_dtor(T) yields true 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 cv-void.
- __is_base_of(T, U) yields true 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.
- __is_convertible(T, U) yields true if 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), cv-void or any combination thereof.
Many thanks to Howard Hinnant for providing base document for this proposal and for explaining why __is_convertible is defined the way it is.