Doc. no.: J16/030006 = WG21/N1424
Previous Doc. no.: J16/020003 = WG21/N1345
Date: 03 March 2003
Project: Programming Language C++
Wiki: http://www.research.att.com/~austern/cgibin/wiki?TypeTraits
Reply to: John Maddock <john_maddock@compuserve.com>
Motivation Impact on the Standard Design Separate classes, or a single monolithic class? Are Boolean properties integralconstant expressions or types? Templates or intrinsic operators? Selection of templates Compiler Support Revision History Unresolved Issues Proposed Text Requirements Unary Type Traits Relationships Between Types Transformations Between Type References Acknowledgements
This proposal forms part of the "infrastructure" of the standard library; it attempts to standardize templates that are often reinvented as bespoke solutions. These templates may be used by the end user, and are often used heavily by library implementers, including those who are writing third party libraries. There are three main use cases that help explain the motivation behind this proposal:
Sometimes templates are not quite as "generic" as one would wish. The problem is that not all types are created equally, implying that some categories of types may need special handling. One example of this is a version of std::pair that can hold reference types[1]. The boost compressed_pair class[2] is a more advanced example of this; as well as being able to hold reference types, it will inherit from, rather than contain, empty classes in order to take advantage of the "zero sized base class optimisation".
Often there is a contract that the template parameters to a class or function must obey. Usually if the template argument does not conform to the contract then the template will fail to compile. Often in such cases the position of the error may be deep inside several layers of template code, and it is often not at all easy for the user to deduce what the problem is, and whether it is their problem or the library's. One solution proposed for this is the idea of conceptchecks[3], however a simpler solution is often possible using a static assertion[4]. For example the following code uses the boost type traits library to insist that the iterator arguments have random access semantics; if an error occurs then it will be generated early on in the procedure being instantiated, and can be commented with a description of the problem:
#include <iterator> #include <boost/static_assert.hpp> #include <boost/type_traits.hpp> template <class RandomAccessIterator > RandomAccessIterator foo(RandomAccessIterator from, RandomAccessIterator to) { // this template can only be used with // random access iterators, attempting to // use some other iterator type will result in // an error message here: typedef typename std::iterator_traits <RandomAccessIterator>::iterator_category cat; typedef int this_is_a_static_assertion[ ::boost::is_convertible< cat*, std::random_access_iterator_tag* >::value ? 1 : 1]; // // detail goes here... // return from; }
Static assertions form part of a separate proposal[10].
The classic example here is the algorithm std::copy
; if the types being copied are POD's, then std::memcpy
can be used to copy the data, rather than a slower "object by object" copy. The boost library has one example of this approach[1]. However this is by no means the only example: the SGI standard library[7] uses a type traits mechanism to achieve the same effect, while the Dinkumware standard library uses a function overloading approach to dispatch to the correct std::copy
implementation. The fact that several vendors have reinvented this technique suggests that this is an area ripe for standardisation. It should be noted that while it is easiest to give examples of traitsbased optimisations from the standard library, both third party libraries and user code can (and do) make use of these techniques. In the boost libraries for example, 17 of 57 top level headers make use of boost's type traits code either directly or indirectly.
Some real world experience comes from the Metrowerks standard library, Howard Hinnant reports: "The Metrowerks "STL" makes fairly heavy use of type traits for optimization purposes, especially the traits that test for trivial member functions (e.g. has_trivial_copy). We also use add_reference extensively in <algorithm> in order to support the issues outlined in [12]"
This is basically a pure extension, it does not require any modification to existing standard library headers, and does not require any core language changes. However some of the templates listed in this proposal can not be fully implemented without some help from the compiler. The proposed text does not specify how this help is provided, and as a temporary measure sufficient lattitude is granted in the proposal to ensure that it is possible to provide an implementation that conforms to the semantics given, without compiler help (see the boost reference implementation[5]). Those templates that benefit from compiler help are noted below.
There following key design decisions to be made in this proposal:
The boost type traits library (and this proposal) uses a separate traits class for each trait, where as, for example, both Loki[6] and the SGI type traits library[7] use a single type_traits class with multiple members. There are a number of advantages to the separate traits class approach:
Finally it should be noted that Loki's author has shifted away from a single type_traits class and towards separate classes in a type_traits namespace[9].
This approach contrasts with that of the current traits classes in the standard library (numeric_limits, and iterator_traits), these existing traits classes are closed for extention, where as type traits are more like an extensible concept, than a finite set of properties (as is the case for numeric_limits for example).
The boost type traits library originally used a static const bool
to represent each true/false condition, where as the SGI type traits library[7] uses a type (__true_type
or __false_type
). The use of a type is more convenient for use with function overloading, whereas the use of an integral constant expression makes it much easier to combine traits using logical expressions  something that has been often found to be necessary during the development of the boost library. The following example shows how std::copy can be optimized by combining value based type traits:
// // copy: // same semantics as std::copy // calls memcpy where appropriate. // namespace detail{ template <bool b> struct copier { template<typename I1, typename I2> static I2 do_copy(I1 first, I1 last, I2 out) { while(first != last) { *out = *first; ++out; ++first; } return out; } }; template <> struct copier<true> { template<typename I1, typename I2> static I2* do_copy(I1* first, I1* last, I2* out) { memcpy(out, first, (lastfirst)*sizeof(I2)); return out+(lastfirst); } }; } template<typename I1, typename I2> inline I2 copy(I1 first, I1 last, I2 out) { typedef typename boost::remove_cv<typename std::iterator_traits<I1>::value_type>::type v1_t; typedef typename boost::remove_cv<typename std::iterator_traits<I2>::value_type>::type v2_t; return detail::copier< ::boost::is_same<v1_t, v2_t>::value && ::boost::is_pointer<I1>::value && ::boost::is_pointer<I2>::value && ::boost::has_trivial_assign<v1_t>::value >::do_copy(first, last, out); }
There is one potential problem with integral constant members that should be raised however: these require an out of line definition as well as an inline initialization (but see core issues 48 and 82). If static const bool
members are used, then one implementation strategy that avoids the problem of having to provide lots of definitions for these static members, would be to have the traits classes inherit from a common base class:
template <class T, T v> struct integral_constant{ static const T value = v; }; template <class T, T v> T integral_constant<T,v>::value; typedef integral_constant<bool, true> true_type; typedef integral_constant<bool, false> false_type; template <class T> struct is_void : public false_type {}; template <> struct is_void<void> : public true_type {}; // etc
Note that there is no requirement to implement the traits classes in this manner: an enum could be used here in place of a static const bool
. This scheme does however make it trivial to select a function overload based on whether a traits class inherits from true_type
or false_type
.
An important use case for providing a type representation for the result of Boolean traits comes from the template metaprogramming, the discipline where class templates are treated as compiletime invocable entities (metafunctions), and where experience has shown that to build a consistent and coherent framework of wellinterpolating components it's crucially important for the metafunctions to provide a single common form of invocation [11]. Since it is possible to wrap an integral constant in a type, but not viceversa, the implementation of boost type traits library was rewritten to provide the result of Boolean trait templates through both their static const bool value
member and the nested type
typedef exposing the corresponding specialization of an integral constant type wrapper.
This proposal follows the boost traits library approach; the template and typedefs:
template <class T, T v> integral_constant; typedef integral_constant<bool, true> true_type; typedef integral_constant<bool, false> false_type;
have been added to act as typebased aliases for integral constant expressions. Likewise the type_traits requirements and descriptions have been updated to make use of this helper template, for example:
template <class T> struct is_void{ static const bool value = implementation defined; typedef bool value_type; typedef integral_constant<value_type, value> type; };
This gives us the best of both worlds, allowing the programmer to use either a type or a value depending upon whichever is the most convenient. For example the std::copy example could be implemented as follows:
template<typename T> T* do_copy(const T* first, const T* last, T* out, const true_type&) { /* optimised copy here */ } template<typename I1, typename I2, bool b> I2 do_copy(I1 first, I1 last, I2 out, const integral_const<bool,b>&) { /* nonoptimised copy here */ } template<typename I1, typename I2> inline I2 copy(I1 first, I1 last, I2 out) { typedef typename std::iterator_traits<I1>::value_type value_type; typedef typename has_trivial_assign<value_type>::type trivial_assign; return do_copy(first, last, out, trivial_assign()); }
This example can be simplified even further if we insist that for each trait X, then X is implicitly convertible to X::type: this can be accomplished in one of two ways: by inheritance from a common base class (as above), or by providing a member conversion operator:
template <class T> struct is_void{ static const bool value = implementation defined; typedef bool value_type; typedef integral_constant<value_type, value> type; operator type()const; };
This proposal does not specify which method should be used, but it does specify that the conversion is possible; even though this is merely a convenience it is nonetheless a useful one. The std::copy example can now be simplified further still:
template<typename T> T* do_copy(const T* first, const T* last, T* out, const true_type&) { /* optimised copy here */ } template<typename I1, typename I2, bool b> I2 do_copy(I1 first, I1 last, I2 out, const integral_constant<bool,b>&) { /* nonoptimised copy here */ } template<typename I1, typename I2> inline I2 copy(I1 first, I1 last, I2 out) { typedef typename std::iterator_traits<I1>::value_type value_type; return do_copy(first, last, out, has_trivial_assign<value_type>()); }
There has been some fairly intense discussion on boost mailing list about the is_convertible template, one suggestion was that since only expressions (and not types) are convertible to a type or not, that is_convertible should be an intrinsic binary operator whose first argument was an expression, and whose second was a type. There are two key advantages to this approach: it more closely mirrors the text of the standard, and therefore standard wording is easier to formulate, and the result can be context sensitive:
class B; class A { A(const B&); /* details omitted */ };
Here class B is convertible to A only within the scope of A; if is_convertible
is a template then the one definition rule requires that is_convertible<B,A>::value
have one value only, and must not be sensitive to context.
On the other hand, inspite of its failings, the is_convertible
template has proven to be extremely useful in practice, and only very rarely does a corner case arise where it fails to do the right thing. The template also appears to be easily understood by end users, even if getting the standardese correct is tricky. To put this in perspective there are about 50 uses of the is_convertible
template within the boost library, and none of these would obviously benefit from an operator style of syntax, some examples include:
is_convertible
to determine whether the source type can be implicitly converted to the destination type, if it can then the usual iostream based cast is optimised away. is_convertible
to determine whether a template parameter is a particular named parameter, otherwise the parameter is treated as a positional parameter. is_convertible
is often used to help compose higher level traits classes; for example the lambda library uses this to calculate type promotions. However this functionality could probably be more easily implemented with a typeof operator. is_convertible
in conjunction with static assertions to verify that template arguments have the required properties, and to output an early, well commented error message if they do not. Likewise is_convertible
has been used (outside of boost) to ensure that code "does the right thing", for example the constructor:
template <class T, class Allocator> template <class I> vector<T,Allocator>::vector<I>(I first, I last, const Allocator& a);
Needs to behave differently depending upon whether type I is an iterator or a numeric type. One solution is to default initialise the object, and then perform a compiler time dispatch to different a member function depending upon whether the expression:
is_convertible<I,size_type>::value && is_convertible<I,value_type>::value
is true or not.
The author's belief is that as far as the DR is concerned, the is_convertible
template class is the right way to go; it is better understood, and has shown itself to be useful as compared to an as yet untried intrinsic operator. It also fits well into the current type traits conceptual framework. However, implementers should be encouraged to experiment with an intrinsic convertibility operator, and this subject may need to be revisited prior to the next standard.
There have been requests from the authors of boost’s MPL that the proposal document whether instantiation any of the unary traits class templates in this proposal will result in the instantiation of a template argument that is itself a templateid (there are some metaprogramming idioms [11] where it is important that instantiation does not occur). Section (14.7.1) implies that if it is a precondition that the a template argument be a complete type (because the semantics of the class depend upon it), then instantiation of that argument (if it is a templateid) is essential in order to determine whether the type has a specific property or not. Similary, for those class templates that do not mandate that the template argument(s) are complete types, there are nonetheless implementations that may require that the type is a complete type (for example is_enum
and any other templates that rely upon it). Therefore, mandating that these templates work with incomplete types or with templateid’s which can not be instantiated, results in compiler support being required where it was not required before. Nonetheless MPL's authors believe that this is a sufficiently important problem that some wording requiring traits class templates not to instantiate their template arguments has been added, albeit with latitude permitting instantiation to occur as a temporary workaround until such time as compiler support becomes available.
Perhaps the most difficult part of this proposal is deciding which traits classes should be included. The boost type traits library has undergone several revisions, with some templates being removed and others added. This proposal includes most of the current boost type traits classes along with a small number of others that are motivated by Loki[6].
Several templates that were in the original proposal were removed after feedback from the LWG (add_const, add_volatile, add_cv, add_pointer, add_reference). These were then reinstated after strong complaints from some of boost's users. The rationale is that these templates are all used as compile time functors which transform one type to another, for example Aleksey Gurtovoy provides the following example, which uses the boost metaprogramming library[11] to transform one type list to another, using type traits as compile time functors:
// transforms 'tuple<T1,T2,..,Tn>' // to 'tuple<T1 const&,T2 const&,..,Tn const&>' template< typename Tuple > struct tuple_of_refs { // transform tuple element types typedef typename mpl::transform< typename Tuple::elements, add_reference< add_const<_1> > // here! >::type refs; typedef typename tuple_from_sequence<refs>::type type; }; template< typename Tuple > typename tuple_of_refs<Tuple>::type tuple_ref(Tuple const& t) { return typename tuple_of_refs<Tuple>::type(t); }
Although such uses have been rare up until now, they are becoming much more common, especially with the introduction of metaprogramming frameworks such as boost's MPL. In this context these templates are analogous to those in <functional>, in both cases the implementations are trivial, but unless these are provided in the standard library, users will have to constantly reinvent the same solution. Provision of these templates also allows for compiler warning suppression in a portable manner:
template <class T> class foo { // The following declaration does not produce a // warning if T is already const, or is a reference type: typedef typename std::add_const<T>::type type; /* details omitted */ };
Feedback from the LWG suggested renaming "is_same" to "is_identical", however there was strong feeling among the boost community for retaining is_same, therefore no change has been made.
There have been three late additions to this proposal:
template <class T> struct is_signed; template <class T> struct is_unsigned; template <class T> struct is_abstract;
These additions may need reviewing as the proposal progresses  although no great problems are anticipated from them  in particular is_signed
and is_unsigned
have been part of the Metrowerks type traits library for some time. There have been some fairly persistent requests for the addition of these three templates to boost, and they are likely to added soon.
There have been one or two requests that haven't made it into the proposed text, mainly because these are templates that either don't sit well in the current design structure, or because their usefulness isn't clear. These are documented here in case the committee wants to discuss and/or add these to the text.
From Dave Abrahams:
"Here's another one we need:
has_common_base_class<T,U>::value
This is the one which allows us to explicitly construct empty classes on top of one another. I suppose you could argue that the compiler should just do this automatically with the empty base optimization, but the ABIs of many compilers are now fixed and they will never (for practical purposes) be able to do it."
From Andrei Alexandrescu:
"An important trait that's missing is the transformation same_align_pod, which would yield a POD type with the same alignment requirements as the passedin type. This type would allow one to build a union that obeys specific alignment requirements."
The following templates require compiler support for a fully conforming implementation:
template <class T> struct is_class; template <class T> struct is_union; template <class T> struct is_enum; template <class T> struct is_polymorphic; template <class T> struct is_empty; template <class T> struct has_trivial_constructor; template <class T> struct has_trivial_copy; template <class T> struct has_trivial_assign; template <class T> struct has_trivial_destructor; template <class T> struct has_nothrow_constructor; template <class T> struct has_nothrow_copy; template <class T> struct has_nothrow_assign; template <class T> struct is_pod; template <class T> struct is_abstract;
In all of these cases however, a nearlyconforming implementation can be provided without any compiler support (see the boost reference implementation [5]), in addition temporary latitude is provided in the proposed TR text to permit a libraryonly implementation (see implementation requirements).
This text does not specify how the compiler support is provided, and nor will it do so, as the author believes that this is overspecification. There are multiple methods for providing this support, the relative merits of which probably depend most upon the compiler's internal structure. To put this in perspective, library vendors will need to do only a small amount of library configuration if they need to support multiple compilers, where as specifying the method used would entail duplicating a large portion of the existing descriptions in this text, increasing the maintenance cost, and the likelihood of defects.
To date three vendors provide some degree of compiler type traits support:
__type_traits
class, allowing for full implementations of is_pod
, has_trivial_constructor
, has_trivial_copy
, has_trivial_assign
and has_trivial_destructor
. is_enum
, is_union
, is_function
, is_class
, has_trivial_copy
, has_trivial_assign
and has_trivial_destructor
. Howard Hinnant reports that adding support has been straightforward using builtin operators such as __builtin_type
, and that using builtin operators is an order of magnitude faster than using a more complex but portable libraryonly solution. Metrowerks' report that they are continuing to add new builtin operators as and when their standard library can make some use of them. __is_scalar(T)
, which evaluates to an integral constant depending upon the type T. Phil Edwards reports that these mostly require very simple oneline implementations; these facilities will form part of an official gcc developmentbranch shortly. Added comparison to numeric_limits and iterator traits design.
Added discussion on is_convertible.
Rewritten the compiler support section: added comments on existing implementations.
Allow implementation of integral members as integral constant expressions, not necessarily as static const bool's.
Added section on implementation variance to permit a conforming implementation within the current language.
Clarified language on use of T and cvqualified T.
Removed permission for user defined specialisations of type categories.
is_float renamed is_floating_point.
is_member_pointer demoted to a composite type category; added is_member_object_pointer and is_member_function_pointer to the primary type category traits.
Removed all the author's explanitory notes.
Simplified definition of is_compound.
Renamed has_nothrow_construct has_nothrow_constructor for consistency with has_trivial_constructor.
Rewritten definition of nonthrowing text, may still not be quite right.
Renamed is_base_and_derived to is_base_of: this change has caused a fair amout of controversy, with many boosters prefering the more verbose original name.
Renamed is_POD to is_pod for consistency with other alllowercase names.
Added additional members type
, value_type
and operator type
, to Unary and binary type traits.
Added the new templates is_unsigned, is_signed and is_abstract.
Added section(s) on template class instantiation.
It is unclear what the name of is_base_of should be: this is called is_base_and_derived in the boost library  the intent is that the name is so explicit that the user can't get the template parameters the wrong way around  likewise it is easier on users reading someone else's code. However there is no getting around the fact that this is an extremely verbose name, so perhaps is_base_of is a better choice.
Is is unclear how remove_pointer should behave with pointers to member (functions). Since there are no such types as "member" or "member function returning type" (you can't dereference member pointers for example), the current version is logical in leaving member pointers unchanged. However one boost user has requested that remove_pointer<T (U::*)>::type evaluates to T, on the grounds that this transformation is sometimes useful.
It is unclear whether the newly added template is_abstract requires compiler support or not, to be on the safe side it is listed as requiring support, but this may be removed at a later date.
This clause describes components used by C++ programs, particularly in templates, to: support the widest possible range of types, optimise template code usage, and detect type related user errors.
The type library provides three facilities: access to the properties of a particular type, access to the relationships (if any) between two types, and transformations from one type to another; as summarised in table TT1
Clause 
Header 


<type_traits> 

<type_compare> 

<type_transform> 
In table TT2, X is a class template that is a unary type trait and T is any arbitrary type.
Expression 
Return type 
Requirement 
X<T>::value 
bool 
An integral constant expression that is true if T has the specified trait, and false otherwise. 
X<T>::value_type 
bool 
A type that is the type of X<T>::value, this is always bool for UnaryTypeTraits. 
X<T>::type 
integral_constant<bool,value> 
A type for use in situations where a typename is more appropriate than a value. The class template integral_constant is declared in <type_traits>. 
X<T>::type t = X<T>() 

Both lvalues of 
In table TT3, X is a class template that is a binary type trait and T and U are any arbitrary types.
Expression 
Return type 
Requirement 
X<T,U>::value 
bool 
An integral constant expression that is true if T is related to U by the relation specified, and false otherwise. 
X<T,U>::value_type 
bool 
A type that is the type of X<T,U>::value, this is always bool for BinaryTypeTraits. 
X<T,U>::type 
integral_constant<bool,value> 
A type for use in situations where a typename is more appropriate than a value. The class template integral_constant is declared in <type_traits>. 
X<T,U>::type t = X<T,U>() 

Both lvalues of type 
In table TT4, X is a class template that is a transformation trait and T is any arbitrary type.
Expression 
Requirement 
X<T>::type 
The result is a type that is the result of applying transformation X to type T. 
This subclause contains templates that may be used to query the properties of a type at compile time.
All of the class templates defined in this header satisfy the UnaryTypeTrait requirements.
For all of the class templates declared in this clause, all members declared static const
shall be defined in such a way that they are usable as integral constant expressions.
For all of the class templates X
declared in this clause, both rvalues of type X const
and lvalues of type X const&
shall be implicitly convertible to X::type
. Whether this is accomplished by inheritance or by a member operator is unspecified. For exposition only the class templates in this clause are shown with a member conversion operator:
operator type() const;
which shall return type()
in all cases.
For all of the class templates X
declared in this clause, instantiating that template with a templateargument that is a class template specialization, may result in the implicit instantiation of the template argument if and only if the semantics of X require that the argument must be a complete type.
namespace std{ // helper class: template <class T, T v> struct integral_constant; typedef integral_constant<bool, true> true_type; typedef integral_constant<bool, false> false_type; // Primary type categories: template <class T> struct is_void; template <class T> struct is_integral; template <class T> struct is_floating_point; template <class T> struct is_array; template <class T> struct is_pointer; template <class T> struct is_reference; template <class T> struct is_member_object_pointer; template <class T> struct is_member_function_pointer; template <class T> struct is_enum; template <class T> struct is_union; template <class T> struct is_class; template <class T> struct is_function; // composite type categories: template <class T> struct is_arithmetic; template <class T> struct is_fundamental; template <class T> struct is_object; template <class T> struct is_scalar; template <class T> struct is_compound; template <class T> struct is_member_pointer; // type properties: template <class T> struct is_const; template <class T> struct is_volatile; template <class T> struct is_pod; template <class T> struct is_empty; template <class T> struct is_polymorphic; template <class T> struct is_abstract; template <class T> struct has_trivial_constructor; template <class T> struct has_trivial_copy; template <class T> struct has_trivial_assign; template <class T> struct has_trivial_destructor; template <class T> struct has_nothrow_constructor; template <class T> struct has_nothrow_copy; template <class T> struct has_nothrow_assign; template <class T> struct is_signed; template <class T> struct is_unsigned; } // namespace std
template <class T, T v> struct integral_constant { static const T value = v; typedef T value_type; typedef integral_constant<T,v> type; }; typedef integral_constant<bool, true> true_type; typedef integral_constant<bool, false> false_type;
The class template integral_constant
and its associated typedefs true_type
and false_type
are for use in situations where a type rather than a value is required.
The primary type categories correspond to the descriptions given in section 3.9.
For any given type T, exactly one of the primary type categories shall have its member value
evaluate to true.
For any given type T, the result of applying one of these templates to T
, and to cvqualified T
shall yield the same result.
Undefined behaviour results if any C++ program adds specializations for any of the class templates defined in this clause.
template <class T> struct is_void { static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is void or a cvqualified void. Otherwise defined to be false.
template <class T> struct is_integral { static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is an integral type (3.9.1). Otherwise defined to be false.
template <class T> struct is_floating_point { static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is a floating point type (3.9.1). Otherwise defined to be false.
template <class T> struct is_array { static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is an array type (3.9.2). Otherwise defined to be false.
template <class T> struct is_pointer { static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is a pointer type (3.9.2), this includes all function pointer types, but not pointers to members or member functions. Otherwise defined to be false.
template <class T> struct is_reference { static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is a reference type (3.9.2), this includes all reference to function types. Otherwise defined to be false.
template <class T> struct is_member_object_pointer { static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is a pointer to a data member. Otherwise defined to be false.
template <class T> struct is_member_function_pointer { static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is a pointer to a member function. Otherwise defined to be false.
template <class T> struct is_enum { static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is an enumeration type (3.9.2). Otherwise defined to be false.
template <class T> struct is_union { static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is a union type (3.9.2). Otherwise defined to be false.
template <class T> struct is_class { static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is a class type (3.9.2), in this context unions are not considered to be class types. Otherwise defined to be false.
template <class T> struct is_function { static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is a function type (3.9.2). Otherwise defined to be false.
These templates provide convenient compositions of the primary type categories, corresponding to the descriptions given in section 3.9.
For any given type T, the result of applying one of these templates to T
, and to cvqualified T
shall yield the same result.
Undefined behaviour results if any C++ program adds specializations for any of the class templates defined in this clause.
template <class T> struct is_arithmetic { static const bool value = is_integral<T>::value  is_floating_point<T>::value; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is an arithmetic type (3.9.1). Otherwise defined to be false.
template <class T> struct is_fundamental{ static const bool value = is_integral<T>::value  is_floating_point<T>::value  is_void<T>::value; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is a fundamental type (3.9.1). Otherwise defined to be false.
template <class T> struct is_object{ static const bool value = !(is_function<T>::value  is_reference<T>::value  is_void<T>::value); typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is an object type (3.9). Otherwise defined to be false.
template <class T> struct is_scalar{ static const bool value = is_arithmetic<T>::value  is_enum<T>::value  is_pointer<T>::value  is_member_pointer<T>::value; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is a scalar type (3.9). Otherwise defined to be false.
template <class T> struct is_compound{ static const bool value = !is_fundamental<T>::value; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is a compound type (3.9.2). Otherwise defined to be false.
template <class T> struct is_member_pointer { static const bool value = is_member_object_pointer<T>::value  is_member_function_pointer<T>::value; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is a pointer to a member or member function. Otherwise defined to be false.
These templates provide access to some of the more important properties of types; they reveal information which is available to the compiler, but which would not otherwise be detectable in C++ code.
Except where specified, it is undefined whether any of these templates have any full or partial specialisations defined. It is permitted for the user to specialise any of these templates on a userdefined type, provided the semantics of the specialisation match those given for the template in its description.
template <class T> struct is_const{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is constqualified (3.9.3). Otherwise defined to be false.
template <class T> struct is_volatile{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is volatilequalified (3.9.3). Otherwise defined to be false.
template <class T> struct is_pod{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
Preconditions: template argument T
shall be a complete type.
value
: defined to be true if T is a POD type (3.9). Otherwise defined to be false.
template <class T> struct is_empty{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
Preconditions: template argument T
shall be a complete type.
value
: defined to be true if T is an empty class (10). Otherwise defined to be false.
template <class T> struct is_polymorphic{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
Preconditions: template argument T
shall be a complete type.
value
: defined to be true if T is a polymorphic class (10.3). Otherwise defined to be false.
template <class T> struct is_abstract{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
Preconditions: template argument T
shall be a complete type.
value
: defined to be true if T is a abstract class (10.4). Otherwise defined to be false.
template <class T> struct has_trivial_constructor{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
Preconditions: template argument T
shall be a complete type.
value
: defined to be true if the default constructor for T is trivial(12.1). Otherwise defined to be false.
template <class T> struct has_trivial_copy{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
Preconditions: template argument T
shall be a complete type.
value
: defined to be true if the copy constructor for T is trivial (12.8). Otherwise defined to be false.
template <class T> struct has_trivial_assign{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
Preconditions: template argument T
shall be a complete type.
value
: defined to be true if the assignment operator for T is trivial (12.8). Otherwise defined to be false.
template <class T> struct has_trivial_destructor{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
Preconditions: template argument T
shall be a complete type.
value
: defined to be true if the destructor for T is trivial (12.4). Otherwise defined to be false.
template <class T> struct has_nothrow_constructor{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
Preconditions: template argument T
shall be a complete type.
value
: defined to be true if the default constructor for T has an empty exception specification, or can otherwise be deduced never to throw an exception. Otherwise defined to be false.
template <class T> struct has_nothrow_copy{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
Preconditions: template argument T
shall be a complete type.
value
: defined to be true if the copy constructor for T has an empty exception specification, or can otherwise be deduced never to throw an exception. Otherwise defined to be false.
template <class T> struct has_nothrow_assign{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
Preconditions: template argument T
shall be a complete type.
value
: defined to be true if the assignment operator for T has an empty exception specification, or can otherwise be deduced never to throw an exception. Otherwise defined to be false.
template <class T> struct is_signed{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is a signed integral type (3.9.1). Otherwise defined to be false.
template <class T> struct is_unsigned{ static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T is an unsigned integral type (3.9.1). Otherwise defined to be false.
This subclause contains templates that may be used to query the relationships between two types at compile time.
All of the templates in this header satisfy the BinaryTypeTrait requirements.
For all of the class templates declared in this clause, all members declared static const shall be defined in such a way that they are usable as integral constant expressions.
For all of the class templates X
declared in this clause, both rvalues of type X const
and lvalues of type X const&
shall be implicitly convertible to X::type
. Whether this is accomplished by inheritance or by a member operator is unspecified. For exposition only the class templates in this clause are shown with a member conversion operator:
operator type() const;
which shall return type()
in all cases.
namespace std{ // helper classes: template <class T, T v> struct integral_constant; typedef integral_constant<bool, true> true_type; typedef integral_constant<bool, false> false_type; // type relations: template <class T, class U> struct is_same; template <class From, class To> struct is_convertible; template <class Base, class Derived> struct is_base_of; } // namespace std
Inclusion of the header <type_compare>
shall make the type integral_constant
, and it’s associated typedefs true_type
and false_type
defined in <type_traits>
visible. Whether any other types declared in <type_traits>
are made visible by the inclusion of <type_compare>
is implementation defined.
template <class T, class U> struct is_same{ static const bool value = false; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; }; template <class T> struct is_same<T,T>{ static const bool value = true; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true if T and U are the same type. Otherwise defined to be false.
template <class From, class To> struct is_convertible { static const bool value = implementation_defined; typedef bool value_type; typedef integral_constant<value_type,value> type; operator type()const; };
value
: defined to be true only if an imaginary lvalue of type From
is implicitlyconvertible to type To
(4.0). Otherwise defined to be false. Special conversions involving stringliterals and nullpointer constants are not considered (4.2, 4.10 and 4.11). No functionparameter adjustments (8.3.5) are made to type To
when determining whether From
is convertible to To
: this implies that if type To
is a function type or an array type, then value
must necessarily evaluate to false.
The expression is_convertible<From,To>::value
is illformed if:
Type From
, is a void or incomplete type (3.9).
Type To
, is an incomplete, void or abstract type (3.9).
The conversion is ambiguous, for example if type From
has multiple base classes of type To
(10.2).
Type To
is of class type and the conversion would invoke a nonpublic constructor of To
(11.0 and 12.3.1).
Type From
is of class type and the conversion would invoke a nonpublic conversion operator of From
(11.0 and 12.3.2).
template < class Base, class Derived> struct is_base_of {
static const bool value = implementation_defined
;
typedef bool value_type;
typedef integral_constant<value_type,value> type;
operator type()const;
};
Preconditions: template arguments Base
and Derived
shall both be complete types.
value
: defined to be true only if type Base
is a base class of type Derived
(10). Otherwise defined to be false.
This subclause contains templates that may be used to transform one type to another following some predefined rule.
All of the templates in this header satisfy the TransformationTrait requirements.
namespace std{ // constvolatile modifications: template <class T> struct remove_const; template <class T> struct remove_volatile; template <class T> struct remove_cv; template <class T> struct add_const; template <class T> struct add_volatile; template <class T> struct add_cv; // reference modifications: template <class T> struct remove_reference; template <class T> struct add_reference; // array modifications: template <class T> struct remove_bounds; // pointer modifications: template <class T> struct remove_pointer; template <class T> struct add_pointer; } // namespace std
template <class T> struct remove_const{ typedef T type; }; template <class T> struct remove_const<T const>{ typedef T type; };
type
: defined to be a type that is the same as T, except that any top level constqualifier has been removed. For example: remove_const<const volatile int>::type
evaluates to volatile int,
where as remove_const<const int*>
is const int*
.
template <class T> struct remove_volatile{ typedef T type; }; template <class T> struct remove_volatile<T volatile>{ typedef T type; };
type
: defined to be a type that is the same as T, except that any top level volatilequalifier has been removed. For example: remove_const<const volatile int>::type
evaluates to const int,
where as remove_const<volatile int*>
is volatile int*
.
template <class T> struct remove_cv{ typedef typename remove_const<typename remove_volatile<T>::type>::type type; };
type
: defined to be a type that is the same as T, except that any top level cvqualifiers have been removed. For example: remove_cv<const volatile int>::type
evaluates to int,
where as remove_cv<const volatile int*>
is const volatile int*
.
template <class T> struct add_const{ typedef T const type; };
type
: if T is a reference, function, or top level constqualified type, then the same type as T, otherwise T const.
template <class T> struct add_volatile{ typedef T volatile type; };
type:
if T is a reference, function, or top level constqualified type, then the same type as T
, otherwise T volatile.
template <class T> struct add_cv{
typedef typename add_const< typename add_volatile<T>::type >::type type;
};
type:
the same type as add_const< add_volatile<T>::type >::type.
template <class T> struct remove_reference{ typedef T type; }; template <class T> struct remove_reference<T&>{ typedef T type; };
type
: defined to be a type that is the same as T, except any reference qualifier has been removed.
template <class T> struct add_reference{ typedef T& type; }; template <class T> struct add_reference<T&>{ typedef T& type; };
type: if T is a reference type, then T, otherwise T&.
template <class T> struct remove_bounds{ typedef T type; }; template <class T, std::size_t N> struct remove_bounds<T[N]>{ typedef T type; };
type
: defined to be a type that is the same as T, except any top level array bounds have been removed.
template <class T> struct remove_pointer{ typedef T type; }; template <class T> struct remove_pointer<T*>{ typedef T type; }; template <class T> struct remove_pointer<T* const>{ typedef T type; }; template <class T> struct remove_pointer<T* volatile>{ typedef T type; }; template <class T> struct remove_pointer<T* const volatile>{ typedef T type; };
type
: defined to be a type that is the same as T, except any top level indirection has been removed. Note: pointers to members are left unchanged by remove_pointer
.
template <class T> struct add_pointer{ typedef typename remove_bounds<typename remove_reference<T>::type>::type* type; };
type
: defined to be a type that is the result of the expression &t
, where t
is an imaginary lvalue of type T.
The behaviour of all the class templates defined in <type_traits>, <type_compare> and <type_transform> shall conform to the specifications given, except where noted below.
The latitude granted to implementers in this clause is temporary, and will be removed in future revisions of this document.
If there is no means by which the implementation can differentiate between class and union types, then the class templates is_class
and is_union
need not be provided.
If there is no means by which the implementation can detect polymorphic types, then the class template is_polymorphic
need not be provided.
If there is no means by which the implementation can detect abstract types, then the class template is_abstract
need not be provided.
It is unspecified under what circumstances, if any, is_empty<T>::value
evaluates to true.
It is unspecified under what circumstances, if any, is_pod<T>::value
evaluates to true, except that, for all types T:
is_pod<T>::value == is_pod<remove_bounds<T>::type>::value is_pod<T>::value == is_pod<T const volatile>::value is_pod<T>::value >= (is_scalar<T>::value  is_void<T>::value)
It is unspecified under what circumstances, if any, has_trivial_*<T>::value
evaluates to true, except that:
has_trivial_*<T>::value == has_trivial_*<remove_bounds<T>::type>::value has_trivial_*<T>::value >= is_pod<T>::value
It is unspecified under what circumstances, if any, has_nothrow_*<T>::value
evaluates to true.
There are trait templates whose semantics do not require their argument(s) to be completely defined, nor does such completeness in any way affect the exact definition of the traits class template specializations. However, in the absence of compiler support these traits cannot be implemented without causing implicit instantiation of their arguments; in particular: is_class, is_enum, and is_scalar. For these templates, it is unspecified whether their template argument(s) are implicitly instantiated when the traits class is itself instantiated.
The author is particularly indebted to everyone who has worked on the boost type traits library[5], but also to David Abrahams, Darin Adler, Beman Dawes, Daniel Frey, Aleksey Gurtovoy, Howard Hinnant, Richard Peters, Gabriel Dos Reis and Emily Winch for their helpful comments on various drafts of this document, and to the Library Working Group Reviewers (Martin Sebor, Dietmar Kuehl and Benjamin Kosnik).